From 8e1de17757a204948b8d0ead4990b2602bc81298 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 28 Oct 2013 17:37:10 -0400 Subject: [PATCH 01/16] Create a new pass to resolve named lifetimes; rscope is not only used to indicate when anonymous regions (i.e., &T) are permitted --- src/librustc/driver/driver.rs | 7 +- src/librustc/middle/resolve_lifetime.rs | 321 ++++++++++++++++++ src/librustc/middle/ty.rs | 5 + src/librustc/middle/typeck/astconv.rs | 189 +++++------ src/librustc/middle/typeck/rscope.rs | 319 ++--------------- src/libsyntax/ast.rs | 14 + src/libsyntax/visit.rs | 103 +++++- .../compile-fail/regions-name-duplicated.rs | 15 + src/test/compile-fail/regions-name-static.rs | 15 + .../compile-fail/regions-name-undeclared.rs | 60 ++++ 10 files changed, 644 insertions(+), 404 deletions(-) create mode 100644 src/librustc/middle/resolve_lifetime.rs create mode 100644 src/test/compile-fail/regions-name-duplicated.rs create mode 100644 src/test/compile-fail/regions-name-static.rs create mode 100644 src/test/compile-fail/regions-name-undeclared.rs diff --git a/src/librustc/driver/driver.rs b/src/librustc/driver/driver.rs index c57cd134e01b6..380991266822c 100644 --- a/src/librustc/driver/driver.rs +++ b/src/librustc/driver/driver.rs @@ -239,6 +239,9 @@ pub fn phase_3_run_analysis_passes(sess: Session, time(time_passes, "resolution", (), |_| middle::resolve::resolve_crate(sess, lang_items, crate)); + let named_region_map = time(time_passes, "lifetime resolution", (), + |_| middle::resolve_lifetime::crate(sess, crate)); + time(time_passes, "looking for entry point", (), |_| middle::entry::find_entry_point(sess, crate, ast_map)); @@ -251,8 +254,8 @@ pub fn phase_3_run_analysis_passes(sess: Session, let rp_set = time(time_passes, "region parameterization inference", (), |_| middle::region::determine_rp_in_crate(sess, ast_map, def_map, crate)); - let ty_cx = ty::mk_ctxt(sess, def_map, ast_map, freevars, - region_map, rp_set, lang_items); + let ty_cx = ty::mk_ctxt(sess, def_map, named_region_map, ast_map, freevars, + region_map, lang_items); // passes are timed inside typeck let (method_map, vtable_map) = typeck::check_crate( diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs new file mode 100644 index 0000000000000..98260be990230 --- /dev/null +++ b/src/librustc/middle/resolve_lifetime.rs @@ -0,0 +1,321 @@ +// Copyright 2012-2013 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. + +/*! + * Name resolution for lifetimes. + * + * Name resolution for lifetimes follows MUCH simpler rules than the + * full resolve. For example, lifetime names are never exported or + * used between functions, and they operate in a purely top-down + * way. Therefore we break lifetime name resolution into a separate pass. + */ + +use driver::session; +use std::hashmap::HashMap; +use syntax::ast; +use syntax::codemap::Span; +use syntax::opt_vec::OptVec; +use syntax::parse::token::special_idents; +use syntax::print::pprust::{lifetime_to_str}; +use syntax::visit; +use syntax::visit::Visitor; + +// maps the id of each lifetime reference to the lifetime decl +// that it corresponds to +pub type NamedRegionMap = HashMap; + +struct LifetimeContext { + sess: session::Session, + named_region_map: @mut NamedRegionMap, +} + +enum ScopeChain<'self> { + ItemScope(&'self OptVec), + FnScope(ast::NodeId, &'self OptVec, &'self ScopeChain<'self>), + BlockScope(ast::NodeId, &'self ScopeChain<'self>), + RootScope +} + +pub fn crate(sess: session::Session, + crate: &ast::Crate) + -> @mut NamedRegionMap { + let mut ctxt = LifetimeContext { + sess: sess, + named_region_map: @mut HashMap::new() + }; + visit::walk_crate(&mut ctxt, crate, &RootScope); + sess.abort_if_errors(); + ctxt.named_region_map +} + +impl<'self> Visitor<&'self ScopeChain<'self>> for LifetimeContext { + fn visit_item(&mut self, + item: @ast::item, + _: &'self ScopeChain<'self>) { + let scope = match item.node { + ast::item_fn(*) | // fn lifetimes get added in visit_fn below + ast::item_mod(*) | + ast::item_mac(*) | + ast::item_foreign_mod(*) | + ast::item_static(*) => { + RootScope + } + ast::item_ty(_, ref generics) | + ast::item_enum(_, ref generics) | + ast::item_struct(_, ref generics) | + ast::item_impl(ref generics, _, _, _) | + ast::item_trait(ref generics, _, _) => { + self.check_lifetime_names(&generics.lifetimes); + ItemScope(&generics.lifetimes) + } + }; + debug!("entering scope {:?}", scope); + visit::walk_item(self, item, &scope); + debug!("exiting scope {:?}", scope); + } + + fn visit_fn(&mut self, + fk: &visit::fn_kind, + fd: &ast::fn_decl, + b: &ast::Block, + s: Span, + n: ast::NodeId, + scope: &'self ScopeChain<'self>) { + match *fk { + visit::fk_item_fn(_, generics, _, _) | + visit::fk_method(_, generics, _) => { + let scope1 = FnScope(n, &generics.lifetimes, scope); + self.check_lifetime_names(&generics.lifetimes); + debug!("pushing fn scope id={} due to item/method", n); + visit::walk_fn(self, fk, fd, b, s, n, &scope1); + debug!("popping fn scope id={} due to item/method", n); + } + visit::fk_anon(*) | visit::fk_fn_block(*) => { + visit::walk_fn(self, fk, fd, b, s, n, scope); + } + } + } + + fn visit_ty(&mut self, + ty: &ast::Ty, + scope: &'self ScopeChain<'self>) { + match ty.node { + ast::ty_closure(@ast::TyClosure { lifetimes: ref lifetimes, _ }) | + ast::ty_bare_fn(@ast::TyBareFn { lifetimes: ref lifetimes, _ }) => { + let scope1 = FnScope(ty.id, lifetimes, scope); + self.check_lifetime_names(lifetimes); + debug!("pushing fn scope id={} due to type", ty.id); + visit::walk_ty(self, ty, &scope1); + debug!("popping fn scope id={} due to type", ty.id); + } + _ => { + visit::walk_ty(self, ty, scope); + } + } + } + + fn visit_ty_method(&mut self, + m: &ast::TypeMethod, + scope: &'self ScopeChain<'self>) { + let scope1 = FnScope(m.id, &m.generics.lifetimes, scope); + self.check_lifetime_names(&m.generics.lifetimes); + debug!("pushing fn scope id={} due to ty_method", m.id); + visit::walk_ty_method(self, m, &scope1); + debug!("popping fn scope id={} due to ty_method", m.id); + } + + fn visit_block(&mut self, + b: &ast::Block, + scope: &'self ScopeChain<'self>) { + let scope1 = BlockScope(b.id, scope); + debug!("pushing block scope {}", b.id); + visit::walk_block(self, b, &scope1); + debug!("popping block scope {}", b.id); + } + + fn visit_lifetime_ref(&mut self, + lifetime_ref: &ast::Lifetime, + scope: &'self ScopeChain<'self>) { + if lifetime_ref.ident == special_idents::statik { + self.insert_lifetime(lifetime_ref, ast::DefStaticRegion); + return; + } + self.resolve_lifetime_ref(lifetime_ref, scope); + } +} + +impl LifetimeContext { + fn resolve_lifetime_ref(&self, + lifetime_ref: &ast::Lifetime, + scope: &ScopeChain) { + // Walk up the scope chain, tracking the number of fn scopes + // that we pass through, until we find a lifetime with the + // given name or we run out of scopes. If we encounter a code + // block, then the lifetime is not bound but free, so switch + // over to `resolve_free_lifetime_ref()` to complete the + // search. + let mut depth = 0; + let mut scope = scope; + loop { + match *scope { + BlockScope(id, s) => { + return self.resolve_free_lifetime_ref(id, lifetime_ref, s); + } + + RootScope => { + break; + } + + ItemScope(lifetimes) => { + match search_lifetimes(lifetimes, lifetime_ref) { + Some((index, decl_id)) => { + let def = ast::DefTypeBoundRegion(index, decl_id); + self.insert_lifetime(lifetime_ref, def); + return; + } + None => { + break; + } + } + } + + FnScope(id, lifetimes, s) => { + match search_lifetimes(lifetimes, lifetime_ref) { + Some((_index, decl_id)) => { + let def = ast::DefFnBoundRegion(id, depth, decl_id); + self.insert_lifetime(lifetime_ref, def); + return; + } + + None => { + depth += 1; + scope = s; + } + } + } + } + } + + self.unresolved_lifetime_ref(lifetime_ref); + } + + fn resolve_free_lifetime_ref(&self, + scope_id: ast::NodeId, + lifetime_ref: &ast::Lifetime, + scope: &ScopeChain) { + // Walk up the scope chain, tracking the outermost free scope, + // until we encounter a scope that contains the named lifetime + // or we run out of scopes. + let mut scope_id = scope_id; + let mut scope = scope; + let mut search_result = None; + loop { + match *scope { + BlockScope(id, s) => { + scope_id = id; + scope = s; + } + + RootScope => { + break; + } + + ItemScope(lifetimes) => { + search_result = search_lifetimes(lifetimes, lifetime_ref); + break; + } + + FnScope(_, lifetimes, s) => { + search_result = search_lifetimes(lifetimes, lifetime_ref); + if search_result.is_some() { + break; + } + scope = s; + } + } + } + + match search_result { + Some((_depth, decl_id)) => { + let def = ast::DefFreeRegion(scope_id, decl_id); + self.insert_lifetime(lifetime_ref, def); + } + + None => { + self.unresolved_lifetime_ref(lifetime_ref); + } + } + + } + + fn unresolved_lifetime_ref(&self, + lifetime_ref: &ast::Lifetime) { + self.sess.span_err( + lifetime_ref.span, + format!("use of undeclared lifetime name `'{}`", + self.sess.str_of(lifetime_ref.ident))); + } + + fn check_lifetime_names(&self, lifetimes: &OptVec) { + for i in range(0, lifetimes.len()) { + let lifetime_i = lifetimes.get(i); + + let special_idents = [special_idents::statik]; + for lifetime in lifetimes.iter() { + if special_idents.iter().any(|&i| i == lifetime.ident) { + self.sess.span_err( + lifetime.span, + format!("illegal lifetime parameter name: `{}`", + self.sess.str_of(lifetime.ident))); + } + } + + for j in range(i + 1, lifetimes.len()) { + let lifetime_j = lifetimes.get(j); + + if lifetime_i.ident == lifetime_j.ident { + self.sess.span_err( + lifetime_j.span, + format!("lifetime name `'{}` declared twice in \ + the same scope", + self.sess.str_of(lifetime_j.ident))); + } + } + } + } + + fn insert_lifetime(&self, + lifetime_ref: &ast::Lifetime, + def: ast::DefRegion) { + if lifetime_ref.id == ast::DUMMY_NODE_ID { + self.sess.span_bug(lifetime_ref.span, + "Lifetime reference not renumbered, \ + probably a bug in syntax::fold"); + } + + debug!("lifetime_ref={} id={} resolved to {:?}", + lifetime_to_str(lifetime_ref, + self.sess.intr()), + lifetime_ref.id, + def); + self.named_region_map.insert(lifetime_ref.id, def); + } +} + +fn search_lifetimes(lifetimes: &OptVec, + lifetime_ref: &ast::Lifetime) + -> Option<(uint, ast::NodeId)> { + for (i, lifetime_decl) in lifetimes.iter().enumerate() { + if lifetime_decl.ident == lifetime_ref.ident { + return Some((i, lifetime_decl.id)); + } + } + return None; +} diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index 96bb2897e0e26..09f24b327f439 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -17,6 +17,7 @@ use middle::lang_items::{TyDescStructLangItem, TyVisitorTraitLangItem}; use middle::lang_items::OpaqueStructLangItem; use middle::freevars; use middle::resolve; +use middle::resolve_lifetime; use middle::ty; use middle::subst::Subst; use middle::typeck; @@ -258,6 +259,8 @@ struct ctxt_ { sess: session::Session, def_map: resolve::DefMap, + named_region_map: @mut resolve_lifetime::NamedRegionMap, + region_maps: @mut middle::region::RegionMaps, region_paramd_items: middle::region::region_paramd_items, @@ -919,6 +922,7 @@ pub fn new_ty_hash() -> @mut HashMap { pub fn mk_ctxt(s: session::Session, dm: resolve::DefMap, + named_region_map: @mut resolve_lifetime::NamedRegionMap, amap: ast_map::map, freevars: freevars::freevar_map, region_maps: @mut middle::region::RegionMaps, @@ -926,6 +930,7 @@ pub fn mk_ctxt(s: session::Session, lang_items: middle::lang_items::LanguageItems) -> ctxt { @ctxt_ { + named_region_map: named_region_map, diag: s.diagnostic(), interner: @mut HashMap::new(), next_id: @mut primitives::LAST_PRIMITIVE_ID, diff --git a/src/librustc/middle/typeck/astconv.rs b/src/librustc/middle/typeck/astconv.rs index 45a6d709b04fb..11d995762ee72 100644 --- a/src/librustc/middle/typeck/astconv.rs +++ b/src/librustc/middle/typeck/astconv.rs @@ -23,13 +23,10 @@ * In the check phase, when the @FnCtxt is used as the `AstConv`, * `get_item_ty()` just looks up the item type in `tcx.tcache`. * - * The `RegionScope` trait controls how region references are - * handled. It has two methods which are used to resolve anonymous - * region references (e.g., `&T`) and named region references (e.g., - * `&a.T`). There are numerous region scopes that can be used, but most - * commonly you want either `EmptyRscope`, which permits only the static - * region, or `TypeRscope`, which permits the self region if the type in - * question is parameterized by a region. + * The `RegionScope` trait controls what happens when the user does + * not specify a region in some location where a region is required + * (e.g., if the user writes `&Foo` as a type rather than `&'a Foo`). + * See the `rscope` module for more details. * * Unlike the `AstConv` trait, the region scope can change as we descend * the type. This is to accommodate the fact that (a) fn types are binding @@ -57,20 +54,17 @@ use middle::const_eval; use middle::ty::{substs}; use middle::ty::{ty_param_substs_and_ty}; use middle::ty; -use middle::typeck::rscope::in_binding_rscope; -use middle::typeck::rscope::{RegionScope, RegionError}; -use middle::typeck::rscope::RegionParamNames; +use middle::typeck::rscope; +use middle::typeck::rscope::{RegionScope}; use middle::typeck::lookup_def_tcx; -use std::result; +use std::vec; use syntax::abi::AbiSet; use syntax::{ast, ast_util}; use syntax::codemap::Span; use syntax::opt_vec::OptVec; use syntax::opt_vec; use syntax::print::pprust::{lifetime_to_str, path_to_str}; -use syntax::parse::token::special_idents; -use util::common::indenter; pub trait AstConv { fn tcx(&self) -> ty::ctxt; @@ -81,55 +75,83 @@ pub trait AstConv { fn ty_infer(&self, span: Span) -> ty::t; } -pub fn get_region_reporting_err( +pub fn ast_region_to_region( tcx: ty::ctxt, - span: Span, - a_r: &Option, - res: Result) -> ty::Region + lifetime: &ast::Lifetime) + -> ty::Region { - match res { - result::Ok(r) => r, - result::Err(ref e) => { - let descr = match a_r { - &None => ~"anonymous lifetime", - &Some(ref a) => format!("lifetime {}", - lifetime_to_str(a, tcx.sess.intr())) - }; - tcx.sess.span_err( - span, - format!("Illegal {}: {}", - descr, e.msg)); - e.replacement + let r = match tcx.named_region_map.find(&lifetime.id) { + None => { + // should have been recorded by the `resolve_lifetime` pass + tcx.sess.span_bug(lifetime.span, "unresolved lifetime"); } - } + + Some(&ast::DefStaticRegion) => { + ty::re_static + } + + Some(&ast::DefFnBoundRegion(binder_id, _, id)) => { + ty::re_fn_bound(binder_id, ty::br_named(ast_util::local_def(id), + lifetime.ident)) + } + + Some(&ast::DefTypeBoundRegion(index, id)) => { + ty::re_type_bound(id, index, lifetime.ident) + } + + Some(&ast::DefFreeRegion(scope_id, id)) => { + ty::re_free(ty::FreeRegion { + scope_id: scope_id, + bound_region: ty::br_named(ast_util::local_def(id), + lifetime.ident) + }) + } + }; + + debug!("ast_region_to_region(lifetime={} id={}) yields {}", + lifetime_to_str(lifetime, tcx.sess.intr()), + lifetime.id, + r.repr(tcx)); + + r } -pub fn ast_region_to_region( +pub fn opt_ast_region_to_region( this: &AC, rscope: &RS, default_span: Span, opt_lifetime: &Option) -> ty::Region { - let (span, res) = match opt_lifetime { - &None => { - (default_span, rscope.anon_region(default_span)) - } - &Some(ref lifetime) if lifetime.ident == special_idents::statik => { - (lifetime.span, Ok(ty::re_static)) + let r = match *opt_lifetime { + Some(ref lifetime) => { + ast_region_to_region(this.tcx(), lifetime) } - &Some(ref lifetime) if lifetime.ident == special_idents::self_ => { - (lifetime.span, rscope.self_region(lifetime.span)) - } - &Some(ref lifetime) => { - (lifetime.span, rscope.named_region(lifetime.span, - lifetime.ident)) + + None => { + match rscope.anon_regions(default_span, 1) { + None => { + debug!("optional region in illegal location"); + this.tcx().sess.span_err( + default_span, "missing lifetime specifier"); + ty::re_static + } + + Some(rs) => { + rs[0] + } + } } }; - get_region_reporting_err(this.tcx(), span, opt_lifetime, res) + debug!("opt_ast_region_to_region(opt_lifetime={:?}) yields {}", + opt_lifetime.as_ref().map( + |e| lifetime_to_str(e, this.tcx().sess.intr())), + r.repr(this.tcx())); + + r } -fn ast_path_substs( +fn ast_path_substs( this: &AC, rscope: &RS, def_id: ast::DefId, @@ -200,7 +222,7 @@ fn ast_path_substs( } pub fn ast_path_to_substs_and_ty( + RS:RegionScope>( this: &AC, rscope: &RS, did: ast::DefId, @@ -217,7 +239,7 @@ pub fn ast_path_to_substs_and_ty( +pub fn ast_path_to_trait_ref( this: &AC, rscope: &RS, trait_def_id: ast::DefId, @@ -240,7 +262,7 @@ pub fn ast_path_to_trait_ref( return trait_ref; } -pub fn ast_path_to_ty( +pub fn ast_path_to_ty( this: &AC, rscope: &RS, did: ast::DefId, @@ -262,10 +284,10 @@ pub static NO_TPS: uint = 2; // Parses the programmer's textual representation of a type into our // internal notion of a type. `getter` is a function that returns the type // corresponding to a definition ID: -pub fn ast_ty_to_ty( +pub fn ast_ty_to_ty( this: &AC, rscope: &RS, ast_ty: &ast::Ty) -> ty::t { - fn ast_mt_to_mt( + fn ast_mt_to_mt( this: &AC, rscope: &RS, mt: &ast::mt) -> ty::mt { ty::mt {ty: ast_ty_to_ty(this, rscope, mt.ty), mutbl: mt.mutbl} @@ -274,7 +296,7 @@ pub fn ast_ty_to_ty( // Handle @, ~, and & being able to mean estrs and evecs. // If a_seq_ty is a str or a vec, make it an estr/evec. // Also handle first-class trait types. - fn mk_pointer( + fn mk_pointer( this: &AC, rscope: &RS, a_seq_ty: &ast::mt, @@ -387,7 +409,8 @@ pub fn ast_ty_to_ty( ty::mk_ptr(tcx, ast_mt_to_mt(this, rscope, mt)) } ast::ty_rptr(ref region, ref mt) => { - let r = ast_region_to_region(this, rscope, ast_ty.span, region); + let r = opt_ast_region_to_region(this, rscope, ast_ty.span, region); + debug!("ty_rptr r={}", r.repr(this.tcx())); mk_pointer(this, rscope, mt, ty::vstore_slice(r), |tmt| ty::mk_rptr(tcx, r, tmt)) } @@ -551,7 +574,7 @@ pub fn ast_ty_to_ty( } pub fn ty_of_arg( + RS:RegionScope>( this: &AC, rscope: &RS, a: &ast::arg, @@ -564,42 +587,12 @@ pub fn ty_of_arg( - this: &AC, - ast_lifetimes: &OptVec) -> OptVec -{ - /*! - * - * Converts a list of lifetimes into a list of bound identifier - * names. Does not permit special names like 'static or 'this to - * be bound. Note that this function is for use in closures, - * methods, and fn definitions. It is legal to bind 'this in a - * type. Eventually this distinction should go away and the same - * rules should apply everywhere ('this would not be a special name - * at that point). - */ - - let special_idents = [special_idents::statik, special_idents::self_]; - let mut bound_lifetime_names = opt_vec::Empty; - ast_lifetimes.map_to_vec(|ast_lifetime| { - if special_idents.iter().any(|&i| i == ast_lifetime.ident) { - this.tcx().sess.span_err( - ast_lifetime.span, - format!("illegal lifetime parameter name: `{}`", - lifetime_to_str(ast_lifetime, this.tcx().sess.intr()))); - } else { - bound_lifetime_names.push(ast_lifetime.ident); - } - }); - bound_lifetime_names -} - struct SelfInfo { untransformed_self_ty: ty::t, explicit_self: ast::explicit_self } -pub fn ty_of_method( +pub fn ty_of_method( this: &AC, rscope: &RS, purity: ast::purity, @@ -643,10 +636,7 @@ fn ty_of_method_or_bare_fn( // new region names that appear inside of the fn decl are bound to // that function type - let bound_lifetime_names = bound_lifetimes(this, lifetimes); - let rb = - in_binding_rscope(rscope, - RegionParamNames(bound_lifetime_names.clone())); + let rb = rscope::BindingRscope::new(id); let opt_transformed_self_ty = do opt_self_info.map |self_info| { transform_self_ty(this, &rb, self_info) @@ -671,7 +661,7 @@ fn ty_of_method_or_bare_fn( } }); - fn transform_self_ty( + fn transform_self_ty( this: &AC, rscope: &RS, self_info: &SelfInfo) -> Option @@ -683,9 +673,9 @@ fn ty_of_method_or_bare_fn( } ast::sty_region(ref lifetime, mutability) => { let region = - ast_region_to_region(this, rscope, - self_info.explicit_self.span, - lifetime); + opt_ast_region_to_region(this, rscope, + self_info.explicit_self.span, + lifetime); Some(ty::mk_rptr(this.tcx(), region, ty::mt {ty: self_info.untransformed_self_ty, mutbl: mutability})) @@ -704,7 +694,7 @@ fn ty_of_method_or_bare_fn( } } -pub fn ty_of_closure( +pub fn ty_of_closure( this: &AC, rscope: &RS, sigil: ast::Sigil, @@ -729,8 +719,8 @@ pub fn ty_of_closure( // resolve the function bound region in the original region // scope `rscope`, not the scope of the function parameters let bound_region = match opt_lifetime { - &Some(_) => { - ast_region_to_region(this, rscope, span, opt_lifetime) + &Some(ref lifetime) => { + ast_region_to_region(this.tcx(), lifetime) } &None => { match sigil { @@ -741,7 +731,7 @@ pub fn ty_of_closure( } ast::BorrowedSigil => { // &fn() defaults as normal for an omitted lifetime: - ast_region_to_region(this, rscope, span, opt_lifetime) + opt_ast_region_to_region(this, rscope, span, opt_lifetime) } } } @@ -749,10 +739,7 @@ pub fn ty_of_closure( // new region names that appear inside of the fn decl are bound to // that function type - let bound_lifetime_names = bound_lifetimes(this, lifetimes); - let rb = - in_binding_rscope(rscope, - RegionParamNames(bound_lifetime_names.clone())); + let rb = rscope::BindingRscope::new(id); let input_tys = do decl.inputs.iter().enumerate().map |(i, a)| { let expected_arg_ty = do expected_sig.as_ref().and_then |e| { diff --git a/src/librustc/middle/typeck/rscope.rs b/src/librustc/middle/typeck/rscope.rs index 1967122745dad..2c48eb04ee6dc 100644 --- a/src/librustc/middle/typeck/rscope.rs +++ b/src/librustc/middle/typeck/rscope.rs @@ -11,312 +11,59 @@ use middle::ty; -use std::result; +use std::vec; use syntax::ast; use syntax::codemap::Span; use syntax::opt_vec::OptVec; -use syntax::opt_vec; -use syntax::parse::token::special_idents; - -#[deriving(ToStr)] -pub struct RegionError { - msg: ~str, - replacement: ty::Region -} pub trait RegionScope { - fn anon_region(&self, span: Span) -> Result; - fn self_region(&self, span: Span) -> Result; - fn named_region(&self, span: Span, id: ast::Ident) - -> Result; -} - -#[deriving(Clone)] -pub struct EmptyRscope; -impl RegionScope for EmptyRscope { - fn anon_region(&self, _span: Span) -> Result { - result::Err(RegionError { - msg: ~"only 'static is allowed here", - replacement: ty::re_static - }) - } - fn self_region(&self, _span: Span) -> Result { - self.anon_region(_span) - } - fn named_region(&self, _span: Span, _id: ast::Ident) - -> Result - { - self.anon_region(_span) - } -} - -#[deriving(Clone)] -pub struct RegionParamNames(OptVec); - -impl RegionParamNames { - fn has_self(&self) -> bool { - self.has_ident(special_idents::self_) - } - - fn has_ident(&self, ident: ast::Ident) -> bool { - for region_param_name in self.iter() { - if *region_param_name == ident { - return true; - } - } - false - } - - pub fn add_generics(&mut self, generics: &ast::Generics) { - match generics.lifetimes { - opt_vec::Empty => {} - opt_vec::Vec(ref new_lifetimes) => { - match **self { - opt_vec::Empty => { - *self = RegionParamNames( - opt_vec::Vec(new_lifetimes.map(|lt| lt.ident))); - } - opt_vec::Vec(ref mut existing_lifetimes) => { - for new_lifetime in new_lifetimes.iter() { - existing_lifetimes.push(new_lifetime.ident); - } - } - } - } - } - } - - // Convenience function to produce the error for an unresolved name. The - // optional argument specifies a custom replacement. - pub fn undeclared_name(custom_replacement: Option) - -> Result { - let replacement = match custom_replacement { - None => ty::re_bound(ty::br_self), - Some(custom_replacement) => custom_replacement - }; - Err(RegionError { - msg: ~"this lifetime must be declared", - replacement: replacement - }) - } - - pub fn from_generics(generics: &ast::Generics) -> RegionParamNames { - match generics.lifetimes { - opt_vec::Empty => RegionParamNames(opt_vec::Empty), - opt_vec::Vec(ref lifetimes) => { - RegionParamNames(opt_vec::Vec(lifetimes.map(|lt| lt.ident))) - } - } - } - - pub fn from_lifetimes(lifetimes: &opt_vec::OptVec) - -> RegionParamNames { - match *lifetimes { - opt_vec::Empty => RegionParamNames::new(), - opt_vec::Vec(ref v) => { - RegionParamNames(opt_vec::Vec(v.map(|lt| lt.ident))) - } - } - } - - fn new() -> RegionParamNames { - RegionParamNames(opt_vec::Empty) - } -} - -#[deriving(Clone)] -struct RegionParameterization { - variance: ty::region_variance, - region_param_names: RegionParamNames, -} - -impl RegionParameterization { - pub fn from_variance_and_generics(variance: Option, - generics: &ast::Generics) - -> Option { - match variance { - None => None, - Some(variance) => { - Some(RegionParameterization { - variance: variance, - region_param_names: - RegionParamNames::from_generics(generics), - }) - } - } - } -} - -#[deriving(Clone)] -pub struct MethodRscope { - explicit_self: ast::explicit_self_, - variance: Option, - region_param_names: RegionParamNames, -} - -impl MethodRscope { - // `generics` here refers to the generics of the outer item (impl or - // trait). - pub fn new(explicit_self: ast::explicit_self_, - variance: Option, - rcvr_generics: &ast::Generics) - -> MethodRscope { - let region_param_names = - RegionParamNames::from_generics(rcvr_generics); - MethodRscope { - explicit_self: explicit_self, - variance: variance, - region_param_names: region_param_names - } - } - - pub fn region_param_names(&self) -> RegionParamNames { - self.region_param_names.clone() - } -} - -impl RegionScope for MethodRscope { - fn anon_region(&self, _span: Span) -> Result { - result::Err(RegionError { - msg: ~"anonymous lifetimes are not permitted here", - replacement: ty::re_bound(ty::br_self) - }) - } - fn self_region(&self, _span: Span) -> Result { - assert!(self.variance.is_some()); - match self.variance { - None => {} // must be borrowed self, so this is OK - Some(_) => { - if !self.region_param_names.has_self() { - return Err(RegionError { - msg: ~"the `self` lifetime must be declared", - replacement: ty::re_bound(ty::br_self) - }) - } - } - } - result::Ok(ty::re_bound(ty::br_self)) - } - fn named_region(&self, span: Span, id: ast::Ident) - -> Result { - if !self.region_param_names.has_ident(id) { - return RegionParamNames::undeclared_name(None); - } - do EmptyRscope.named_region(span, id).or_else |_e| { - result::Err(RegionError { - msg: ~"lifetime is not in scope", - replacement: ty::re_bound(ty::br_self) - }) - } - } + fn anon_regions(&self, + span: Span, + count: uint) + -> Option<~[ty::Region]>; } -#[deriving(Clone)] -pub struct TypeRscope(Option); - -impl TypeRscope { - fn replacement(&self) -> ty::Region { - if self.is_some() { - ty::re_bound(ty::br_self) - } else { - ty::re_static - } - } -} -impl RegionScope for TypeRscope { - fn anon_region(&self, _span: Span) -> Result { - result::Err(RegionError { - msg: ~"anonymous lifetimes are not permitted here", - replacement: self.replacement() - }) - } - fn self_region(&self, _span: Span) -> Result { - match **self { - None => { - // if the self region is used, region parameterization should - // have inferred that this type is RP - fail!("region parameterization should have inferred that \ - this type is RP"); - } - Some(ref region_parameterization) => { - if !region_parameterization.region_param_names.has_self() { - return Err(RegionError { - msg: ~"the `self` lifetime must be declared", - replacement: ty::re_bound(ty::br_self) - }) - } - } - } - result::Ok(ty::re_bound(ty::br_self)) - } - fn named_region(&self, span: Span, id: ast::Ident) - -> Result { - do EmptyRscope.named_region(span, id).or_else |_e| { - result::Err(RegionError { - msg: ~"only 'self is allowed as part of a type declaration", - replacement: self.replacement() - }) - } - } -} +// A scope in which all regions must be explicitly named +pub struct ExplicitRscope; -pub fn bound_self_region(rp: Option) - -> OptVec { - match rp { - Some(_) => opt_vec::with(ty::re_bound(ty::br_self)), - None => opt_vec::Empty +impl RegionScope for ExplicitRscope { + fn anon_regions(&self, + _span: Span, + _count: uint) + -> Option<~[ty::Region]> { + None } } pub struct BindingRscope { - base: @RegionScope, - anon_bindings: @mut uint, - region_param_names: RegionParamNames, + binder_id: ast::NodeId, + anon_bindings: @mut uint } -impl Clone for BindingRscope { - fn clone(&self) -> BindingRscope { +impl BindingRscope { + pub fn new(binder_id: ast::NodeId) -> BindingRscope { BindingRscope { - base: self.base, - anon_bindings: self.anon_bindings, - region_param_names: self.region_param_names.clone(), + binder_id: binder_id, + anon_bindings: @mut 0 } } } -pub fn in_binding_rscope( - this: &RS, - region_param_names: RegionParamNames) - -> BindingRscope { - let base = @(*this).clone(); - let base = base as @RegionScope; - BindingRscope { - base: base, - anon_bindings: @mut 0, - region_param_names: region_param_names, - } -} - impl RegionScope for BindingRscope { - fn anon_region(&self, _span: Span) -> Result { + fn anon_regions(&self, + _: Span, + count: uint) + -> Option<~[ty::Region]> { let idx = *self.anon_bindings; - *self.anon_bindings += 1; - result::Ok(ty::re_bound(ty::br_anon(idx))) - } - fn self_region(&self, span: Span) -> Result { - self.base.self_region(span) - } - fn named_region(&self, - span: Span, - id: ast::Ident) -> Result - { - do self.base.named_region(span, id).or_else |_e| { - let result = ty::re_bound(ty::br_named(id)); - if self.region_param_names.has_ident(id) { - result::Ok(result) - } else { - RegionParamNames::undeclared_name(Some(result)) - } - } + *self.anon_bindings += count; + Some(vec::from_fn(count, |i| ty::re_fn_bound(self.binder_id, + ty::br_anon(idx + i)))) } } + +pub fn bound_type_regions(defs: &[ty::RegionParameterDef]) + -> OptVec { + assert!(defs.iter().all(|def| def.def_id.crate == ast::LOCAL_CRATE)); + defs.iter().enumerate().map( + |(i, def)| ty::re_type_bound(def.def_id.node, i, def.ident)).collect() +} diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 2dd2629048bd3..c0c2e2822f162 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -251,6 +251,20 @@ pub enum Def { DefMethod(DefId /* method */, Option /* trait */), } +#[deriving(Clone, Eq, IterBytes, Encodable, Decodable, ToStr)] +pub enum DefRegion { + DefStaticRegion, + DefTypeBoundRegion(/* index */ uint, /* lifetime decl */ NodeId), + DefFnBoundRegion(/* binder_id */ NodeId, /* depth */ uint, /* lifetime decl */ NodeId), + DefFreeRegion(/* block scope */ NodeId, /* lifetime decl */ NodeId), +} + +#[deriving(Clone, Eq, IterBytes, Encodable, Decodable, ToStr)] +pub struct DefNamedRegion { + node_id: NodeId, + depth: uint, +} + // The set of MetaItems that define the compilation environment of the crate, // used to drive conditional compilation pub type CrateConfig = ~[@MetaItem]; diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index 09ee87d170148..60127be87b6ef 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -90,7 +90,32 @@ pub trait Visitor { walk_struct_def(self, s, i, g, n, e) } fn visit_struct_field(&mut self, s:@struct_field, e:E) { walk_struct_field(self, s, e) } - fn visit_mac(&mut self, m:&mac, e:E) { walk_mac(self, m, e); } + fn visit_opt_lifetime_ref(&mut self, + _span: Span, + opt_lifetime: &Option, + env: E) { + /*! + * Visits an optional reference to a lifetime. The `span` is + * the span of some surrounding reference should opt_lifetime + * be None. + */ + match *opt_lifetime { + Some(ref l) => self.visit_lifetime_ref(l, env), + None => () + } + } + fn visit_lifetime_ref(&mut self, _lifetime: &Lifetime, _e: E) { + /*! Visits a reference to a lifetime */ + } + fn visit_lifetime_decl(&mut self, _lifetime: &Lifetime, _e: E) { + /*! Visits a declaration of a lifetime */ + } + fn visit_explicit_self(&mut self, es: &explicit_self, e: E) { + walk_explicit_self(self, es, e) + } + fn visit_mac(&mut self, macro:&mac, e:E) { + walk_mac(self, macro, e) + } } pub fn walk_crate>(visitor: &mut V, crate: &Crate, env: E) { @@ -119,6 +144,18 @@ pub fn walk_local>(visitor: &mut V, local: &Local, env: E) } } +fn walk_explicit_self>(visitor: &mut V, + explicit_self: &explicit_self, + env: E) { + match explicit_self.node { + sty_static | sty_value(_) | sty_box(_) | sty_uniq(_) => { + } + sty_region(ref lifetime, _) => { + visitor.visit_opt_lifetime_ref(explicit_self.span, lifetime, env) + } + } +} + fn walk_trait_ref>(visitor: &mut V, trait_ref: &ast::trait_ref, env: E) { @@ -221,8 +258,11 @@ pub fn skip_ty>(_: &mut V, _: &Ty, _: E) { pub fn walk_ty>(visitor: &mut V, typ: &Ty, env: E) { match typ.node { ty_box(ref mutable_type) | ty_uniq(ref mutable_type) | - ty_vec(ref mutable_type) | ty_ptr(ref mutable_type) | - ty_rptr(_, ref mutable_type) => { + ty_vec(ref mutable_type) | ty_ptr(ref mutable_type) => { + visitor.visit_ty(mutable_type.ty, env) + } + ty_rptr(ref lifetime, ref mutable_type) => { + visitor.visit_opt_lifetime_ref(typ.span, lifetime, env.clone()); visitor.visit_ty(mutable_type.ty, env) } ty_tup(ref tuple_element_types) => { @@ -231,19 +271,27 @@ pub fn walk_ty>(visitor: &mut V, typ: &Ty, env: E) { } } ty_closure(ref function_declaration) => { - for argument in function_declaration.decl.inputs.iter() { + for argument in function_declaration.decl.inputs.iter() { visitor.visit_ty(&argument.ty, env.clone()) - } - visitor.visit_ty(&function_declaration.decl.output, env.clone()); - for bounds in function_declaration.bounds.iter() { + } + visitor.visit_ty(&function_declaration.decl.output, env.clone()); + for bounds in function_declaration.bounds.iter() { walk_ty_param_bounds(visitor, bounds, env.clone()) - } + } + visitor.visit_opt_lifetime_ref( + typ.span, + &function_declaration.region, + env.clone()); + walk_lifetime_decls(visitor, &function_declaration.lifetimes, + env.clone()); } ty_bare_fn(ref function_declaration) => { for argument in function_declaration.decl.inputs.iter() { visitor.visit_ty(&argument.ty, env.clone()) } - visitor.visit_ty(&function_declaration.decl.output, env.clone()) + visitor.visit_ty(&function_declaration.decl.output, env.clone()); + walk_lifetime_decls(visitor, &function_declaration.lifetimes, + env.clone()); } ty_path(ref path, ref bounds, _) => { walk_path(visitor, path, env.clone()); @@ -262,10 +310,21 @@ pub fn walk_ty>(visitor: &mut V, typ: &Ty, env: E) { } } +fn walk_lifetime_decls>(visitor: &mut V, + lifetimes: &OptVec, + env: E) { + for l in lifetimes.iter() { + visitor.visit_lifetime_decl(l, env.clone()); + } +} + pub fn walk_path>(visitor: &mut V, path: &Path, env: E) { for segment in path.segments.iter() { for typ in segment.types.iter() { - visitor.visit_ty(typ, env.clone()) + visitor.visit_ty(typ, env.clone()); + } + for lifetime in segment.lifetimes.iter() { + visitor.visit_lifetime_ref(lifetime, env.clone()); } } } @@ -354,6 +413,7 @@ pub fn walk_generics>(visitor: &mut V, for type_parameter in generics.ty_params.iter() { walk_ty_param_bounds(visitor, &type_parameter.bounds, env.clone()) } + walk_lifetime_decls(visitor, &generics.lifetimes, env); } pub fn walk_fn_decl>(visitor: &mut V, @@ -385,18 +445,31 @@ pub fn walk_fn>(visitor: &mut V, function_kind: &fn_kind, function_declaration: &fn_decl, function_body: &Block, - _: Span, + _span: Span, _: NodeId, env: E) { walk_fn_decl(visitor, function_declaration, env.clone()); - let generics = generics_of_fn(function_kind); - visitor.visit_generics(&generics, env.clone()); + + match *function_kind { + fk_item_fn(_, generics, _, _) => { + visitor.visit_generics(generics, env.clone()); + } + fk_method(_, generics, method) => { + visitor.visit_generics(generics, env.clone()); + + visitor.visit_explicit_self(&method.explicit_self, env.clone()); + } + fk_anon(*) | fk_fn_block(*) => { + } + } + visitor.visit_block(function_body, env) } pub fn walk_ty_method>(visitor: &mut V, - method_type: &TypeMethod, - env: E) { + method_type: &TypeMethod, + env: E) { + visitor.visit_explicit_self(&method_type.explicit_self, env.clone()); for argument_type in method_type.decl.inputs.iter() { visitor.visit_ty(&argument_type.ty, env.clone()) } diff --git a/src/test/compile-fail/regions-name-duplicated.rs b/src/test/compile-fail/regions-name-duplicated.rs new file mode 100644 index 0000000000000..518fe0b00b6ce --- /dev/null +++ b/src/test/compile-fail/regions-name-duplicated.rs @@ -0,0 +1,15 @@ +// Copyright 2012-2013 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. + +struct Foo<'a, 'a> { //~ ERROR lifetime name `'a` declared twice + x: &'a int +} + +fn main() {} diff --git a/src/test/compile-fail/regions-name-static.rs b/src/test/compile-fail/regions-name-static.rs new file mode 100644 index 0000000000000..c1170654dd294 --- /dev/null +++ b/src/test/compile-fail/regions-name-static.rs @@ -0,0 +1,15 @@ +// Copyright 2012-2013 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. + +struct Foo<'static> { //~ ERROR illegal lifetime parameter name: `static` + x: &'static int +} + +fn main() {} diff --git a/src/test/compile-fail/regions-name-undeclared.rs b/src/test/compile-fail/regions-name-undeclared.rs new file mode 100644 index 0000000000000..abff33e051491 --- /dev/null +++ b/src/test/compile-fail/regions-name-undeclared.rs @@ -0,0 +1,60 @@ +// Copyright 2012-2013 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. + +// Check that lifetime resolver enforces the lifetime name scoping +// rules correctly in various scenarios. + +struct Foo<'a> { + x: &'a int +} + +impl<'a> Foo<'a> { + // &'a is inherited: + fn m1(&self, arg: &'a int) { } + fn m2(&'a self) { } + fn m3(&self, arg: Foo<'a>) { } + + // &'b is not: + fn m4(&self, arg: &'b int) { } //~ ERROR undeclared lifetime + fn m5(&'b self) { } //~ ERROR undeclared lifetime + fn m6(&self, arg: Foo<'b>) { } //~ ERROR undeclared lifetime +} + +fn bar<'a>(x: &'a int) { + // &'a is visible to code: + let y: &'a int = x; + + // &'a is not visible to *items*: + type X = Option<&'a int>; //~ ERROR undeclared lifetime + enum E { + E1(&'a int) //~ ERROR undeclared lifetime + } + struct S { + f: &'a int //~ ERROR undeclared lifetime + } + fn f(a: &'a int) { } //~ ERROR undeclared lifetime + + // &'a CAN be declared on functions and used then: + fn g<'a>(a: &'a int) { } // OK + fn h(a: &fn<'a>(&'a int)) { } // OK +} + +// Test nesting of lifetimes in fn type declarations +fn fn_types(a: &'a int, //~ ERROR undeclared lifetime + b: &fn<'a>(a: &'a int, + b: &'b int, //~ ERROR undeclared lifetime + c: &fn<'b>(a: &'a int, + b: &'b int), + d: &'b int), //~ ERROR undeclared lifetime + c: &'a int) //~ ERROR undeclared lifetime +{ +} + +pub fn main() {} From 85c51d3b02e421e2ab99c330e0d8212293f64f04 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 29 Oct 2013 05:25:18 -0400 Subject: [PATCH 02/16] Introduce ty_fold mechanism and port our various folders to use it. This should eventually be merged with the Subst trait. --- src/librustc/middle/subst.rs | 54 +++-- src/librustc/middle/ty.rs | 405 ++++++++------------------------- src/librustc/middle/ty_fold.rs | 286 +++++++++++++++++++++++ 3 files changed, 411 insertions(+), 334 deletions(-) create mode 100644 src/librustc/middle/ty_fold.rs diff --git a/src/librustc/middle/subst.rs b/src/librustc/middle/subst.rs index 009745ff2adb8..a13248f2480d1 100644 --- a/src/librustc/middle/subst.rs +++ b/src/librustc/middle/subst.rs @@ -10,10 +10,11 @@ // Type substitutions. - use middle::ty; +use middle::ty_fold; +use middle::ty_fold::TypeFolder; use syntax::opt_vec::OptVec; -use util::ppaux::Repr; +use std::at_vec; /////////////////////////////////////////////////////////////////////////// // Public trait `Subst` @@ -33,39 +34,43 @@ pub trait Subst { // to all subst methods but ran into trouble due to the limitations of // our current method/trait matching algorithm. - Niko -trait EffectfulSubst { - fn effectfulSubst(&self, tcx: ty::ctxt, substs: &ty::substs) -> Self; -} - impl Subst for ty::t { fn subst(&self, tcx: ty::ctxt, substs: &ty::substs) -> ty::t { if ty::substs_is_noop(substs) { - return *self; + *self } else { - return self.effectfulSubst(tcx, substs); + let mut folder = SubstFolder {tcx: tcx, substs: substs}; + folder.fold_ty(*self) } } } -impl EffectfulSubst for ty::t { - fn effectfulSubst(&self, tcx: ty::ctxt, substs: &ty::substs) -> ty::t { - if !ty::type_needs_subst(*self) { - return *self; +struct SubstFolder<'self> { + tcx: ty::ctxt, + substs: &'self ty::substs +} + +impl<'self> TypeFolder for SubstFolder<'self> { + fn tcx(&self) -> ty::ctxt { self.tcx } + + fn fold_region(&mut self, r: ty::Region) -> ty::Region { + r.subst(self.tcx, self.substs) + } + + fn fold_ty(&mut self, t: ty::t) -> ty::t { + if !ty::type_needs_subst(t) { + return t; } - match ty::get(*self).sty { + match ty::get(t).sty { ty::ty_param(p) => { - substs.tps[p.idx] + self.substs.tps[p.idx] } ty::ty_self(_) => { - substs.self_ty.expect("ty_self not found in substs") + self.substs.self_ty.expect("ty_self not found in substs") } _ => { - ty::fold_regions_and_ty( - tcx, *self, - |r| r.subst(tcx, substs), - |t| t.effectfulSubst(tcx, substs), - |t| t.effectfulSubst(tcx, substs)) + ty_fold::super_fold_ty(self, t) } } } @@ -80,6 +85,12 @@ impl Subst for ~[T] { } } +impl Subst for @[T] { + fn subst(&self, tcx: ty::ctxt, substs: &ty::substs) -> @[T] { + at_vec::map(*self, |t| t.subst(tcx, substs)) + } +} + impl Subst for OptVec { fn subst(&self, tcx: ty::ctxt, substs: &ty::substs) -> OptVec { self.map(|t| t.subst(tcx, substs)) @@ -134,7 +145,8 @@ impl Subst for ty::RegionSubsts { impl Subst for ty::BareFnTy { fn subst(&self, tcx: ty::ctxt, substs: &ty::substs) -> ty::BareFnTy { - ty::fold_bare_fn_ty(self, |t| t.subst(tcx, substs)) + let mut folder = SubstFolder {tcx: tcx, substs: substs}; + folder.fold_bare_fn_ty(self) } } diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index 09f24b327f439..9d6ad4d8bf694 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -21,6 +21,8 @@ use middle::resolve_lifetime; use middle::ty; use middle::subst::Subst; use middle::typeck; +use middle::ty_fold; +use middle::ty_fold::TypeFolder; use middle; use util::ppaux::{note_and_explain_region, bound_region_ptr_to_str}; use util::ppaux::{trait_store_to_str, ty_to_str, vstore_to_str}; @@ -983,7 +985,7 @@ pub fn mk_ctxt(s: session::Session, // Interns a type/name combination, stores the resulting box in cx.interner, // and returns the box as cast to an unsafe ptr (see comments for t above). -fn mk_t(cx: ctxt, st: sty) -> t { +pub fn mk_t(cx: ctxt, st: sty) -> t { // Check for primitive types. match st { ty_nil => return mk_nil(), @@ -992,6 +994,8 @@ fn mk_t(cx: ctxt, st: sty) -> t { ty_int(i) => return mk_mach_int(i), ty_uint(u) => return mk_mach_uint(u), ty_float(f) => return mk_mach_float(f), + ty_char => return mk_char(), + ty_bot => return mk_bot(), _ => {} }; @@ -1338,224 +1342,70 @@ pub fn maybe_walk_ty(ty: t, f: &fn(t) -> bool) { } } -pub fn fold_sty_to_ty(tcx: ty::ctxt, sty: &sty, foldop: &fn(t) -> t) -> t { - mk_t(tcx, fold_sty(sty, foldop)) +// Folds types from the bottom up. +pub fn fold_ty(cx: ctxt, t0: t, fldop: &fn(t) -> t) -> t { + let mut f = ty_fold::BottomUpFolder {tcx: cx, fldop: fldop}; + f.fold_ty(t0) } -pub fn fold_sig(sig: &FnSig, fldop: &fn(t) -> t) -> FnSig { - let args = sig.inputs.map(|arg| fldop(*arg)); - - FnSig { - bound_lifetime_names: sig.bound_lifetime_names.clone(), - inputs: args, - output: fldop(sig.output), - variadic: sig.variadic - } +pub fn walk_regions_and_ty(cx: ctxt, + ty: t, + fldr: &fn(r: Region), + fldt: &fn(t: t)) + -> t { + ty_fold::RegionFolder::general(cx, + |r| { fldr(r); r }, + |t| { fldt(t); t }).fold_ty(ty) } -pub fn fold_bare_fn_ty(fty: &BareFnTy, fldop: &fn(t) -> t) -> BareFnTy { - BareFnTy {sig: fold_sig(&fty.sig, fldop), - abis: fty.abis, - purity: fty.purity} +pub fn fold_regions(cx: ctxt, + ty: t, + fldr: &fn(r: Region) -> Region) + -> t { + ty_fold::RegionFolder::regions(cx, fldr).fold_ty(ty) } -fn fold_sty(sty: &sty, fldop: &fn(t) -> t) -> sty { - fn fold_substs(substs: &substs, fldop: &fn(t) -> t) -> substs { - substs {regions: substs.regions.clone(), - self_ty: substs.self_ty.map(|t| fldop(t)), - tps: substs.tps.map(|t| fldop(*t))} - } +// Substitute *only* type parameters. Used in trans where regions are erased. +pub fn subst_tps(tcx: ctxt, tps: &[t], self_ty_opt: Option, typ: t) -> t { + let mut subst = TpsSubst { tcx: tcx, self_ty_opt: self_ty_opt, tps: tps }; + return subst.fold_ty(typ); - match *sty { - ty_box(ref tm) => { - ty_box(mt {ty: fldop(tm.ty), mutbl: tm.mutbl}) - } - ty_uniq(ref tm) => { - ty_uniq(mt {ty: fldop(tm.ty), mutbl: tm.mutbl}) - } - ty_ptr(ref tm) => { - ty_ptr(mt {ty: fldop(tm.ty), mutbl: tm.mutbl}) - } - ty_unboxed_vec(ref tm) => { - ty_unboxed_vec(mt {ty: fldop(tm.ty), mutbl: tm.mutbl}) - } - ty_evec(ref tm, vst) => { - ty_evec(mt {ty: fldop(tm.ty), mutbl: tm.mutbl}, vst) - } - ty_enum(tid, ref substs) => { - ty_enum(tid, fold_substs(substs, fldop)) - } - ty_trait(did, ref substs, st, mutbl, bounds) => { - ty_trait(did, fold_substs(substs, fldop), st, mutbl, bounds) - } - ty_tup(ref ts) => { - let new_ts = ts.map(|tt| fldop(*tt)); - ty_tup(new_ts) - } - ty_bare_fn(ref f) => { - ty_bare_fn(fold_bare_fn_ty(f, fldop)) - } - ty_closure(ref f) => { - let sig = fold_sig(&f.sig, fldop); - ty_closure(ClosureTy { - sig: sig, - purity: f.purity, - sigil: f.sigil, - onceness: f.onceness, - region: f.region, - bounds: f.bounds, - }) - } - ty_rptr(r, ref tm) => { - ty_rptr(r, mt {ty: fldop(tm.ty), mutbl: tm.mutbl}) - } - ty_struct(did, ref substs) => { - ty_struct(did, fold_substs(substs, fldop)) - } - ty_nil | ty_bot | ty_bool | ty_char | ty_int(_) | ty_uint(_) | ty_float(_) | - ty_estr(_) | ty_type | ty_opaque_closure_ptr(_) | ty_err | - ty_opaque_box | ty_infer(_) | ty_param(*) | ty_self(_) => { - (*sty).clone() - } + pub struct TpsSubst<'self> { + tcx: ctxt, + self_ty_opt: Option, + tps: &'self [t], } -} -// Folds types from the bottom up. -pub fn fold_ty(cx: ctxt, t0: t, fldop: &fn(t) -> t) -> t { - let sty = fold_sty(&get(t0).sty, |t| fold_ty(cx, fldop(t), |t| fldop(t))); - fldop(mk_t(cx, sty)) -} - -pub fn walk_regions_and_ty( - cx: ctxt, - ty: t, - walkr: &fn(r: Region), - walkt: &fn(t: t) -> bool) { - - if (walkt(ty)) { - fold_regions_and_ty( - cx, ty, - |r| { walkr(r); r }, - |t| { walk_regions_and_ty(cx, t, |r| walkr(r), |t| walkt(t)); t }, - |t| { walk_regions_and_ty(cx, t, |r| walkr(r), |t| walkt(t)); t }); - } -} + impl<'self> TypeFolder for TpsSubst<'self> { + fn tcx(&self) -> ty::ctxt { self.tcx } -pub fn fold_regions_and_ty( - cx: ctxt, - ty: t, - fldr: &fn(r: Region) -> Region, - fldfnt: &fn(t: t) -> t, - fldt: &fn(t: t) -> t) -> t { - - fn fold_substs( - substs: &substs, - fldr: &fn(r: Region) -> Region, - fldt: &fn(t: t) -> t) - -> substs { - let regions = match substs.regions { - ErasedRegions => ErasedRegions, - NonerasedRegions(ref regions) => { - NonerasedRegions(regions.map(|r| fldr(*r))) + fn fold_ty(&mut self, t: ty::t) -> ty::t { + if self.tps.len() == 0u && self.self_ty_opt.is_none() { + return t; } - }; - substs { - regions: regions, - self_ty: substs.self_ty.map(|t| fldt(t)), - tps: substs.tps.map(|t| fldt(*t)) - } - } + let tb = ty::get(t); + if self.self_ty_opt.is_none() && !tbox_has_flag(tb, has_params) { + return t; + } - let tb = ty::get(ty); - match tb.sty { - ty::ty_rptr(r, mt) => { - let m_r = fldr(r); - let m_t = fldt(mt.ty); - ty::mk_rptr(cx, m_r, mt {ty: m_t, mutbl: mt.mutbl}) - } - ty_estr(vstore_slice(r)) => { - let m_r = fldr(r); - ty::mk_estr(cx, vstore_slice(m_r)) - } - ty_evec(mt, vstore_slice(r)) => { - let m_r = fldr(r); - let m_t = fldt(mt.ty); - ty::mk_evec(cx, mt {ty: m_t, mutbl: mt.mutbl}, vstore_slice(m_r)) - } - ty_enum(def_id, ref substs) => { - ty::mk_enum(cx, def_id, fold_substs(substs, fldr, fldt)) - } - ty_struct(def_id, ref substs) => { - ty::mk_struct(cx, def_id, fold_substs(substs, fldr, fldt)) - } - ty_trait(def_id, ref substs, st, mutbl, bounds) => { - let st = match st { - RegionTraitStore(region) => RegionTraitStore(fldr(region)), - st => st, - }; - ty::mk_trait(cx, def_id, fold_substs(substs, fldr, fldt), st, mutbl, bounds) - } - ty_bare_fn(ref f) => { - ty::mk_bare_fn(cx, BareFnTy { - sig: fold_sig(&f.sig, fldfnt), - purity: f.purity, - abis: f.abis.clone(), - }) - } - ty_closure(ref f) => { - ty::mk_closure(cx, ClosureTy { - region: fldr(f.region), - sig: fold_sig(&f.sig, fldfnt), - purity: f.purity, - sigil: f.sigil, - onceness: f.onceness, - bounds: f.bounds, - }) - } - ref sty => { - fold_sty_to_ty(cx, sty, |t| fldt(t)) - } - } -} + match ty::get(t).sty { + ty_param(p) => { + self.tps[p.idx] + } -// n.b. this function is intended to eventually replace fold_region() below, -// that is why its name is so similar. -pub fn fold_regions( - cx: ctxt, - ty: t, - fldr: &fn(r: Region, in_fn: bool) -> Region) -> t { - fn do_fold(cx: ctxt, ty: t, in_fn: bool, - fldr: &fn(Region, bool) -> Region) -> t { - debug!("do_fold(ty={}, in_fn={})", ty_to_str(cx, ty), in_fn); - if !type_has_regions(ty) { return ty; } - fold_regions_and_ty( - cx, ty, - |r| fldr(r, in_fn), - |t| do_fold(cx, t, true, |r,b| fldr(r,b)), - |t| do_fold(cx, t, in_fn, |r,b| fldr(r,b))) - } - do_fold(cx, ty, false, fldr) -} + ty_self(_) => { + match self.self_ty_opt { + None => self.tcx.sess.bug("ty_self unexpected here"), + Some(self_ty) => self_ty + } + } -// Substitute *only* type parameters. Used in trans where regions are erased. -pub fn subst_tps(cx: ctxt, tps: &[t], self_ty_opt: Option, typ: t) -> t { - if tps.len() == 0u && self_ty_opt.is_none() { return typ; } - let tb = ty::get(typ); - if self_ty_opt.is_none() && !tbox_has_flag(tb, has_params) { return typ; } - match tb.sty { - ty_param(p) => tps[p.idx], - ty_self(_) => { - match self_ty_opt { - None => cx.sess.bug("ty_self unexpected here"), - Some(self_ty) => { - subst_tps(cx, tps, self_ty_opt, self_ty) + _ => { + ty_fold::super_fold_ty(self, t) } } } - ref sty => { - fold_sty_to_ty(cx, sty, |t| subst_tps(cx, tps, self_ty_opt, t)) - } } } @@ -2727,55 +2577,6 @@ pub fn index_sty(sty: &sty) -> Option { } } -/** - * Enforces an arbitrary but consistent total ordering over - * free regions. This is needed for establishing a consistent - * LUB in region_inference. */ -impl cmp::TotalOrd for FreeRegion { - fn cmp(&self, other: &FreeRegion) -> Ordering { - cmp::cmp2(&self.scope_id, &self.bound_region, - &other.scope_id, &other.bound_region) - } -} - -impl cmp::TotalEq for FreeRegion { - fn equals(&self, other: &FreeRegion) -> bool { - *self == *other - } -} - -/** - * Enforces an arbitrary but consistent total ordering over - * bound regions. This is needed for establishing a consistent - * LUB in region_inference. */ -impl cmp::TotalOrd for bound_region { - fn cmp(&self, other: &bound_region) -> Ordering { - match (self, other) { - (&ty::br_self, &ty::br_self) => cmp::Equal, - (&ty::br_self, _) => cmp::Less, - - (&ty::br_anon(ref a1), &ty::br_anon(ref a2)) => a1.cmp(a2), - (&ty::br_anon(*), _) => cmp::Less, - - (&ty::br_named(ref a1), &ty::br_named(ref a2)) => a1.name.cmp(&a2.name), - (&ty::br_named(*), _) => cmp::Less, - - (&ty::br_cap_avoid(ref a1, @ref b1), - &ty::br_cap_avoid(ref a2, @ref b2)) => cmp::cmp2(a1, b1, a2, b2), - (&ty::br_cap_avoid(*), _) => cmp::Less, - - (&ty::br_fresh(ref a1), &ty::br_fresh(ref a2)) => a1.cmp(a2), - (&ty::br_fresh(*), _) => cmp::Less, - } - } -} - -impl cmp::TotalEq for bound_region { - fn equals(&self, other: &bound_region) -> bool { - *self == *other - } -} - pub fn node_id_to_trait_ref(cx: ctxt, id: ast::NodeId) -> @ty::TraitRef { match cx.trait_refs.find(&id) { Some(&t) => t, @@ -3684,7 +3485,6 @@ fn lookup_locally_or_in_crate_store( load_external: &fn() -> V) -> V { /*! - * * Helper for looking things up in the various maps * that are populated during typeck::collect (e.g., * `cx.methods`, `cx.tcache`, etc). All of these share @@ -3694,8 +3494,8 @@ fn lookup_locally_or_in_crate_store( * the crate loading code (and cache the result for the future). */ - match map.find(&def_id) { - Some(&ref v) => { return (*v).clone(); } + match map.find_copy(&def_id) { + Some(v) => { return v; } None => { } } @@ -3733,7 +3533,7 @@ pub fn method(cx: ctxt, id: ast::DefId) -> @Method { pub fn trait_method_def_ids(cx: ctxt, id: ast::DefId) -> @~[DefId] { lookup_locally_or_in_crate_store( - "methods", id, cx.trait_method_def_ids, + "trait_method_def_ids", id, cx.trait_method_def_ids, || @csearch::get_trait_method_def_ids(cx.cstore, id)) } @@ -4359,77 +4159,56 @@ pub fn ty_params_to_tys(tcx: ty::ctxt, generics: &ast::Generics) -> ~[t] { /// Returns an equivalent type with all the typedefs and self regions removed. pub fn normalize_ty(cx: ctxt, t: t) -> t { - fn normalize_mt(cx: ctxt, mt: mt) -> mt { - mt { ty: normalize_ty(cx, mt.ty), mutbl: mt.mutbl } - } - fn normalize_vstore(vstore: vstore) -> vstore { - match vstore { - vstore_fixed(*) | vstore_uniq | vstore_box => vstore, - vstore_slice(_) => vstore_slice(re_static) - } - } - - match cx.normalized_cache.find(&t) { - Some(&t) => return t, - None => () - } - - let t = match get(t).sty { - ty_evec(mt, vstore) => - // This type has a vstore. Get rid of it - mk_evec(cx, normalize_mt(cx, mt), normalize_vstore(vstore)), + let u = TypeNormalizer(cx).fold_ty(t); + return u; - ty_estr(vstore) => - // This type has a vstore. Get rid of it - mk_estr(cx, normalize_vstore(vstore)), + struct TypeNormalizer(ctxt); - ty_rptr(_, mt) => - // This type has a region. Get rid of it - mk_rptr(cx, re_static, normalize_mt(cx, mt)), + impl TypeFolder for TypeNormalizer { + fn tcx(&self) -> ty::ctxt { **self } - ty_closure(ref closure_ty) => { - mk_closure(cx, ClosureTy { - region: ty::re_static, - ..(*closure_ty).clone() - }) - } - - ty_enum(did, ref r) => { - match (*r).regions { - NonerasedRegions(_) => { - // trans doesn't care about regions - mk_enum(cx, did, substs {regions: ty::ErasedRegions, - self_ty: None, - tps: (*r).tps.clone()}) + fn fold_ty(&mut self, t: ty::t) -> ty::t { + match self.tcx().normalized_cache.find_copy(&t) { + Some(u) => { + return u; } - ErasedRegions => { - t + None => { + let t_norm = ty_fold::super_fold_ty(self, t); + self.tcx().normalized_cache.insert(t, t_norm); + return t_norm; } } } - ty_struct(did, ref r) => { - match (*r).regions { - NonerasedRegions(_) => { - // Ditto. - mk_struct(cx, did, substs {regions: ty::ErasedRegions, - self_ty: None, - tps: (*r).tps.clone()}) - } - ErasedRegions => { - t - } + fn fold_vstore(&mut self, vstore: vstore) -> vstore { + match vstore { + vstore_fixed(*) | vstore_uniq | vstore_box => vstore, + vstore_slice(_) => vstore_slice(re_static) } } - _ => - t - }; + fn fold_region(&mut self, _: ty::Region) -> ty::Region { + ty::re_static + } + + fn fold_substs(&mut self, + substs: &substs) + -> substs { + substs { regions: ErasedRegions, + self_ty: ty_fold::fold_opt_ty(self, substs.self_ty), + tps: ty_fold::fold_ty_vec(self, substs.tps) } + } - let sty = fold_sty(&get(t).sty, |t| { normalize_ty(cx, t) }); - let t_norm = mk_t(cx, sty); - cx.normalized_cache.insert(t, t_norm); - return t_norm; + fn fold_sig(&mut self, + sig: &ty::FnSig) + -> ty::FnSig { + // The binder-id is only relevant to bound regions, which + // are erased at trans time. + ty::FnSig { binder_id: ast::DUMMY_NODE_ID, + inputs: ty_fold::fold_ty_vec(self, sig.inputs), + output: self.fold_ty(sig.output) } + } + } } pub trait ExprTyProvider { diff --git a/src/librustc/middle/ty_fold.rs b/src/librustc/middle/ty_fold.rs new file mode 100644 index 0000000000000..dc4fca0176a5f --- /dev/null +++ b/src/librustc/middle/ty_fold.rs @@ -0,0 +1,286 @@ +// Copyright 2012-2013 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. + +// Generalized type folding mechanism. + +use middle::ty; +use util::ppaux::Repr; + +pub trait TypeFolder { + fn tcx(&self) -> ty::ctxt; + + fn fold_ty(&mut self, t: ty::t) -> ty::t { + super_fold_ty(self, t) + } + + fn fold_mt(&mut self, t: &ty::mt) -> ty::mt { + super_fold_mt(self, t) + } + + fn fold_trait_ref(&mut self, t: &ty::TraitRef) -> ty::TraitRef { + super_fold_trait_ref(self, t) + } + + fn fold_sty(&mut self, sty: &ty::sty) -> ty::sty { + super_fold_sty(self, sty) + } + + fn fold_substs(&mut self, + substs: &ty::substs) + -> ty::substs { + super_fold_substs(self, substs) + } + + fn fold_sig(&mut self, + sig: &ty::FnSig) + -> ty::FnSig { + super_fold_sig(self, sig) + } + + fn fold_bare_fn_ty(&mut self, + fty: &ty::BareFnTy) + -> ty::BareFnTy { + ty::BareFnTy { sig: self.fold_sig(&fty.sig), + abis: fty.abis, + purity: fty.purity } + } + + fn fold_closure_ty(&mut self, + fty: &ty::ClosureTy) + -> ty::ClosureTy { + ty::ClosureTy { + region: self.fold_region(fty.region), + sig: self.fold_sig(&fty.sig), + purity: fty.purity, + sigil: fty.sigil, + onceness: fty.onceness, + bounds: fty.bounds, + } + } + + fn fold_region(&mut self, r: ty::Region) -> ty::Region { + r + } + + fn fold_vstore(&mut self, vstore: ty::vstore) -> ty::vstore { + super_fold_vstore(self, vstore) + } + + fn fold_trait_store(&mut self, s: ty::TraitStore) -> ty::TraitStore { + super_fold_trait_store(self, s) + } +} + +pub fn fold_opt_ty(this: &mut T, + t: Option) + -> Option { + t.map(|t| this.fold_ty(t)) +} + +pub fn fold_ty_vec(this: &mut T, + tys: &[ty::t]) + -> ~[ty::t] { + tys.map(|t| this.fold_ty(*t)) +} + +pub fn super_fold_ty(this: &mut T, + t: ty::t) + -> ty::t { + ty::mk_t(this.tcx(), this.fold_sty(&ty::get(t).sty)) +} + +pub fn super_fold_substs(this: &mut T, + substs: &ty::substs) + -> ty::substs { + let regions = match substs.regions { + ty::ErasedRegions => { + ty::ErasedRegions + } + ty::NonerasedRegions(ref regions) => { + ty::NonerasedRegions(regions.map(|r| this.fold_region(*r))) + } + }; + + ty::substs { regions: regions, + self_ty: fold_opt_ty(this, substs.self_ty), + tps: fold_ty_vec(this, substs.tps), } +} + +pub fn super_fold_sig(this: &mut T, + sig: &ty::FnSig) + -> ty::FnSig { + ty::FnSig { binder_id: sig.binder_id, + inputs: fold_ty_vec(this, sig.inputs), + output: this.fold_ty(sig.output), + variadic: sig.variadic } +} + +pub fn super_fold_trait_ref(this: &mut T, + t: &ty::TraitRef) + -> ty::TraitRef { + ty::TraitRef { + def_id: t.def_id, + substs: this.fold_substs(&t.substs) + } +} + +pub fn super_fold_mt(this: &mut T, + mt: &ty::mt) -> ty::mt { + ty::mt {ty: this.fold_ty(mt.ty), + mutbl: mt.mutbl} +} + +pub fn super_fold_sty(this: &mut T, + sty: &ty::sty) -> ty::sty { + match *sty { + ty::ty_box(ref tm) => { + ty::ty_box(this.fold_mt(tm)) + } + ty::ty_uniq(ref tm) => { + ty::ty_uniq(this.fold_mt(tm)) + } + ty::ty_ptr(ref tm) => { + ty::ty_ptr(this.fold_mt(tm)) + } + ty::ty_unboxed_vec(ref tm) => { + ty::ty_unboxed_vec(this.fold_mt(tm)) + } + ty::ty_evec(ref tm, vst) => { + ty::ty_evec(this.fold_mt(tm), + this.fold_vstore(vst)) + } + ty::ty_enum(tid, ref substs) => { + ty::ty_enum(tid, this.fold_substs(substs)) + } + ty::ty_trait(did, ref substs, st, mutbl, bounds) => { + ty::ty_trait(did, + this.fold_substs(substs), + this.fold_trait_store(st), + mutbl, + bounds) + } + ty::ty_tup(ref ts) => { + ty::ty_tup(fold_ty_vec(this, *ts)) + } + ty::ty_bare_fn(ref f) => { + ty::ty_bare_fn(this.fold_bare_fn_ty(f)) + } + ty::ty_closure(ref f) => { + ty::ty_closure(this.fold_closure_ty(f)) + } + ty::ty_rptr(r, ref tm) => { + ty::ty_rptr(this.fold_region(r), + ty::mt {ty: this.fold_ty(tm.ty), + mutbl: tm.mutbl}) + } + ty::ty_struct(did, ref substs) => { + ty::ty_struct(did, + this.fold_substs(substs)) + } + ty::ty_estr(vst) => { + ty::ty_estr(this.fold_vstore(vst)) + } + ty::ty_nil | ty::ty_bot | ty::ty_bool | ty::ty_char | + ty::ty_int(_) | ty::ty_uint(_) | + ty::ty_float(_) | ty::ty_type | + ty::ty_opaque_closure_ptr(_) | + ty::ty_err | ty::ty_opaque_box | ty::ty_infer(_) | + ty::ty_param(*) | ty::ty_self(_) => { + (*sty).clone() + } + } +} + +pub fn super_fold_vstore(this: &mut T, + vstore: ty::vstore) + -> ty::vstore { + match vstore { + ty::vstore_fixed(i) => ty::vstore_fixed(i), + ty::vstore_uniq => ty::vstore_uniq, + ty::vstore_box => ty::vstore_box, + ty::vstore_slice(r) => ty::vstore_slice(this.fold_region(r)), + } +} + +pub fn super_fold_trait_store(this: &mut T, + trait_store: ty::TraitStore) + -> ty::TraitStore { + match trait_store { + ty::UniqTraitStore => ty::UniqTraitStore, + ty::BoxTraitStore => ty::BoxTraitStore, + ty::RegionTraitStore(r) => ty::RegionTraitStore(this.fold_region(r)), + } +} + +/////////////////////////////////////////////////////////////////////////// +// Some sample folders + +pub struct BottomUpFolder<'self> { + tcx: ty::ctxt, + fldop: &'self fn(ty::t) -> ty::t, +} + +impl<'self> TypeFolder for BottomUpFolder<'self> { + fn tcx(&self) -> ty::ctxt { self.tcx } + + fn fold_ty(&mut self, ty: ty::t) -> ty::t { + let t1 = super_fold_ty(self, ty); + (self.fldop)(t1) + } +} + +/////////////////////////////////////////////////////////////////////////// +// Region folder + +pub struct RegionFolder<'self> { + tcx: ty::ctxt, + fld_t: &'self fn(ty::t) -> ty::t, + fld_r: &'self fn(ty::Region) -> ty::Region, +} + +impl<'self> RegionFolder<'self> { + pub fn general(tcx: ty::ctxt, + fld_r: &'self fn(ty::Region) -> ty::Region, + fld_t: &'self fn(ty::t) -> ty::t) + -> RegionFolder<'self> { + RegionFolder { + tcx: tcx, + fld_t: fld_t, + fld_r: fld_r + } + } + + pub fn regions(tcx: ty::ctxt, + fld_r: &'self fn(ty::Region) -> ty::Region) + -> RegionFolder<'self> { + fn noop(t: ty::t) -> ty::t { t } + + RegionFolder { + tcx: tcx, + fld_t: noop, + fld_r: fld_r + } + } +} + +impl<'self> TypeFolder for RegionFolder<'self> { + fn tcx(&self) -> ty::ctxt { self.tcx } + + fn fold_ty(&mut self, ty: ty::t) -> ty::t { + debug!("RegionFolder.fold_ty({})", ty.repr(self.tcx())); + let t1 = super_fold_ty(self, ty); + (self.fld_t)(t1) + } + + fn fold_region(&mut self, r: ty::Region) -> ty::Region { + debug!("RegionFolder.fold_region({})", r.repr(self.tcx())); + (self.fld_r)(r) + } +} From 1f4faaee401f8681e25afbcf3b6296b6cd2ca55a Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 29 Oct 2013 06:03:32 -0400 Subject: [PATCH 03/16] Generalize AST and ty::Generics to accept multiple lifetimes. --- src/librustc/front/std_inject.rs | 4 +- src/librustc/front/test.rs | 4 +- src/librustc/lib.rs | 2 + src/librustc/metadata/common.rs | 5 + src/librustc/metadata/csearch.rs | 8 +- src/librustc/metadata/decoder.rs | 58 +- src/librustc/metadata/encoder.rs | 34 +- src/librustc/metadata/tydecode.rs | 108 ++-- src/librustc/metadata/tyencode.rs | 48 +- src/librustc/middle/astencode.rs | 53 +- .../middle/borrowck/gather_loans/mod.rs | 3 +- src/librustc/middle/kind.rs | 3 +- src/librustc/middle/privacy.rs | 2 +- src/librustc/middle/resolve.rs | 2 +- src/librustc/middle/subst.rs | 35 +- src/librustc/middle/ty.rs | 173 ++++-- src/librustc/middle/typeck/astconv.rs | 104 ++-- src/librustc/middle/typeck/check/method.rs | 43 +- src/librustc/middle/typeck/check/mod.rs | 547 ++++++++---------- src/librustc/middle/typeck/check/regionck.rs | 19 +- .../middle/typeck/check/regionmanip.rs | 246 +++----- src/librustc/middle/typeck/check/vtable.rs | 147 ++--- src/librustc/middle/typeck/coherence.rs | 19 +- src/librustc/middle/typeck/collect.rs | 491 +++++++--------- src/librustc/middle/typeck/infer/combine.rs | 26 +- src/librustc/middle/typeck/infer/glb.rs | 95 +-- src/librustc/middle/typeck/infer/lattice.rs | 28 +- src/librustc/middle/typeck/infer/lub.rs | 48 +- src/librustc/middle/typeck/infer/mod.rs | 60 +- .../typeck/infer/region_inference/mod.rs | 88 +-- src/librustc/middle/typeck/infer/resolve.rs | 21 +- src/librustc/middle/typeck/infer/sub.rs | 27 +- src/librustc/middle/typeck/mod.rs | 7 +- src/librustc/util/ppaux.rs | 152 +++-- src/librustdoc/clean.rs | 4 +- src/librustdoc/html/format.rs | 36 +- src/libstd/at_vec.rs | 13 +- src/libsyntax/ast.rs | 10 +- src/libsyntax/ast_map.rs | 12 + src/libsyntax/ast_util.rs | 8 +- src/libsyntax/ext/build.rs | 14 +- src/libsyntax/ext/concat_idents.rs | 2 +- src/libsyntax/ext/deriving/generic.rs | 8 +- src/libsyntax/ext/deriving/rand.rs | 3 +- src/libsyntax/ext/deriving/ty.rs | 18 +- src/libsyntax/ext/expand.rs | 4 +- src/libsyntax/ext/format.rs | 7 +- src/libsyntax/fold.rs | 35 +- src/libsyntax/opt_vec.rs | 10 + src/libsyntax/parse/mod.rs | 20 +- src/libsyntax/parse/parser.rs | 55 +- src/libsyntax/print/pprust.rs | 7 +- 52 files changed, 1516 insertions(+), 1460 deletions(-) diff --git a/src/librustc/front/std_inject.rs b/src/librustc/front/std_inject.rs index b34829bf47fc1..c2d0251b23cc2 100644 --- a/src/librustc/front/std_inject.rs +++ b/src/librustc/front/std_inject.rs @@ -116,12 +116,12 @@ impl fold::ast_fold for StandardLibraryInjector { segments: ~[ ast::PathSegment { identifier: self.sess.ident_of("std"), - lifetime: None, + lifetimes: opt_vec::Empty, types: opt_vec::Empty, }, ast::PathSegment { identifier: self.sess.ident_of("prelude"), - lifetime: None, + lifetimes: opt_vec::Empty, types: opt_vec::Empty, }, ], diff --git a/src/librustc/front/test.rs b/src/librustc/front/test.rs index 9541a03aff25e..b6ae41833777a 100644 --- a/src/librustc/front/test.rs +++ b/src/librustc/front/test.rs @@ -343,7 +343,7 @@ fn path_node(ids: ~[ast::Ident]) -> ast::Path { global: false, segments: ids.move_iter().map(|identifier| ast::PathSegment { identifier: identifier, - lifetime: None, + lifetimes: opt_vec::Empty, types: opt_vec::Empty, }).collect() } @@ -355,7 +355,7 @@ fn path_node_global(ids: ~[ast::Ident]) -> ast::Path { global: true, segments: ids.move_iter().map(|identifier| ast::PathSegment { identifier: identifier, - lifetime: None, + lifetimes: opt_vec::Empty, types: opt_vec::Empty, }).collect() } diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index ba27b5a5f41b1..f2f200affe802 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -53,8 +53,10 @@ use syntax::diagnostic; pub mod middle { pub mod trans; pub mod ty; + pub mod ty_fold; pub mod subst; pub mod resolve; + pub mod resolve_lifetime; pub mod typeck; pub mod check_loop; pub mod check_match; diff --git a/src/librustc/metadata/common.rs b/src/librustc/metadata/common.rs index 6294b6cb6e312..05d40bbb6aea7 100644 --- a/src/librustc/metadata/common.rs +++ b/src/librustc/metadata/common.rs @@ -193,6 +193,11 @@ pub static tag_path_elt_pretty_name: uint = 0x87; pub static tag_path_elt_pretty_name_ident: uint = 0x88; pub static tag_path_elt_pretty_name_extra: uint = 0x89; +pub static tag_region_param_def: uint = 0x100; +pub static tag_region_param_def_ident: uint = 0x101; +pub static tag_region_param_def_def_id: uint = 0x102; + + pub struct LinkMeta { name: @str, vers: @str, diff --git a/src/librustc/metadata/csearch.rs b/src/librustc/metadata/csearch.rs index 48fe21b334395..436b4c3df6bec 100644 --- a/src/librustc/metadata/csearch.rs +++ b/src/librustc/metadata/csearch.rs @@ -199,12 +199,6 @@ pub fn get_trait_def(tcx: ty::ctxt, def: ast::DefId) -> ty::TraitDef { decoder::get_trait_def(cdata, def.node, tcx) } -pub fn get_region_param(cstore: @mut metadata::cstore::CStore, - def: ast::DefId) -> Option { - let cdata = cstore::get_crate_data(cstore, def.crate); - return decoder::get_region_param(cdata, def.node); -} - pub fn get_field_type(tcx: ty::ctxt, class_id: ast::DefId, def: ast::DefId) -> ty::ty_param_bounds_and_ty { let cstore = tcx.cstore; @@ -224,7 +218,7 @@ pub fn get_field_type(tcx: ty::ctxt, class_id: ast::DefId, let ty = decoder::item_type(def, the_field, tcx, cdata); ty::ty_param_bounds_and_ty { generics: ty::Generics {type_param_defs: @~[], - region_param: None}, + region_param_defs: @[]}, ty: ty } } diff --git a/src/librustc/metadata/decoder.rs b/src/librustc/metadata/decoder.rs index 56abaa27cce2c..3b4e29c97c014 100644 --- a/src/librustc/metadata/decoder.rs +++ b/src/librustc/metadata/decoder.rs @@ -25,7 +25,7 @@ use middle::ty; use middle::typeck; use middle::astencode::vtable_decoder_helpers; - +use std::at_vec; use std::u64; use std::rt::io; use std::rt::io::extensions::u64_from_be_bytes; @@ -252,9 +252,11 @@ fn item_trait_ref(doc: ebml::Doc, tcx: ty::ctxt, cdata: Cmd) -> ty::TraitRef { doc_trait_ref(tp, tcx, cdata) } -fn item_ty_param_defs(item: ebml::Doc, tcx: ty::ctxt, cdata: Cmd, +fn item_ty_param_defs(item: ebml::Doc, + tcx: ty::ctxt, + cdata: Cmd, tag: uint) - -> @~[ty::TypeParameterDef] { + -> @~[ty::TypeParameterDef] { let mut bounds = ~[]; do reader::tagged_docs(item, tag) |p| { let bd = parse_type_param_def_data( @@ -266,10 +268,23 @@ fn item_ty_param_defs(item: ebml::Doc, tcx: ty::ctxt, cdata: Cmd, @bounds } -fn item_ty_region_param(item: ebml::Doc) -> Option { - do reader::maybe_get_doc(item, tag_region_param).map |doc| { - let mut decoder = reader::Decoder(doc); - Decodable::decode(&mut decoder) +fn item_region_param_defs(item_doc: ebml::Doc, + tcx: ty::ctxt, + cdata: Cmd) + -> @[ty::RegionParameterDef] { + do at_vec::build(None) |push| { + do reader::tagged_docs(item_doc, tag_region_param_def) |rp_doc| { + let ident_str_doc = reader::get_doc(rp_doc, + tag_region_param_def_ident); + let ident = item_name(tcx.sess.intr(), ident_str_doc); + let def_id_doc = reader::get_doc(rp_doc, + tag_region_param_def_def_id); + let def_id = reader::with_doc_data(def_id_doc, parse_def_id); + let def_id = translate_def_id(cdata, def_id); + push(ty::RegionParameterDef { ident: ident, + def_id: def_id }); + true + }; } } @@ -393,7 +408,7 @@ pub fn get_trait_def(cdata: Cmd, let item_doc = lookup_item(item_id, cdata.data); let tp_defs = item_ty_param_defs(item_doc, tcx, cdata, tag_items_data_item_ty_param_bounds); - let rp = item_ty_region_param(item_doc); + let rp_defs = item_region_param_defs(item_doc, tcx, cdata); let mut bounds = ty::EmptyBuiltinBounds(); // Collect the builtin bounds from the encoded supertraits. // FIXME(#8559): They should be encoded directly. @@ -407,7 +422,7 @@ pub fn get_trait_def(cdata: Cmd, }; ty::TraitDef { generics: ty::Generics {type_param_defs: tp_defs, - region_param: rp}, + region_param_defs: rp_defs}, bounds: bounds, trait_ref: @item_trait_ref(item_doc, tcx, cdata) } @@ -417,33 +432,27 @@ pub fn get_type(cdata: Cmd, id: ast::NodeId, tcx: ty::ctxt) -> ty::ty_param_bounds_and_ty { let item = lookup_item(id, cdata.data); + let t = item_type(ast::DefId { crate: cdata.cnum, node: id }, item, tcx, cdata); - let tp_defs = if family_has_type_params(item_family(item)) { - item_ty_param_defs(item, tcx, cdata, tag_items_data_item_ty_param_bounds) - } else { @~[] }; - let rp = item_ty_region_param(item); + + let tp_defs = item_ty_param_defs(item, tcx, cdata, tag_items_data_item_ty_param_bounds); + let rp_defs = item_region_param_defs(item, tcx, cdata); + ty::ty_param_bounds_and_ty { generics: ty::Generics {type_param_defs: tp_defs, - region_param: rp}, + region_param_defs: rp_defs}, ty: t } } -pub fn get_region_param(cdata: Cmd, id: ast::NodeId) - -> Option { - - let item = lookup_item(id, cdata.data); - return item_ty_region_param(item); -} - pub fn get_type_param_count(data: @~[u8], id: ast::NodeId) -> uint { item_ty_param_count(lookup_item(id, data)) } pub fn get_impl_trait(cdata: Cmd, - id: ast::NodeId, - tcx: ty::ctxt) -> Option<@ty::TraitRef> + id: ast::NodeId, + tcx: ty::ctxt) -> Option<@ty::TraitRef> { let item_doc = lookup_item(id, cdata.data); do reader::maybe_get_doc(item_doc, tag_item_trait_ref).map |tp| { @@ -1044,6 +1053,7 @@ pub fn get_method(intr: @ident_interner, cdata: Cmd, id: ast::NodeId, let name = item_name(intr, method_doc); let type_param_defs = item_ty_param_defs(method_doc, tcx, cdata, tag_item_method_tps); + let rp_defs = item_region_param_defs(method_doc, tcx, cdata); let transformed_self_ty = doc_transformed_self_ty(method_doc, tcx, cdata); let fty = doc_method_fty(method_doc, tcx, cdata); let vis = item_visibility(method_doc); @@ -1054,7 +1064,7 @@ pub fn get_method(intr: @ident_interner, cdata: Cmd, id: ast::NodeId, name, ty::Generics { type_param_defs: type_param_defs, - region_param: None + region_param_defs: rp_defs, }, transformed_self_ty, fty, diff --git a/src/librustc/metadata/encoder.rs b/src/librustc/metadata/encoder.rs index 1ad7e416342f5..76c49da5861e6 100644 --- a/src/librustc/metadata/encoder.rs +++ b/src/librustc/metadata/encoder.rs @@ -121,17 +121,6 @@ pub fn encode_def_id(ebml_w: &mut writer::Encoder, id: DefId) { ebml_w.wr_tagged_str(tag_def_id, def_to_str(id)); } -fn encode_region_param(ecx: &EncodeContext, - ebml_w: &mut writer::Encoder, - it: @ast::item) { - let opt_rp = ecx.tcx.region_paramd_items.find(&it.id); - for rp in opt_rp.iter() { - ebml_w.start_tag(tag_region_param); - rp.encode(ebml_w); - ebml_w.end_tag(); - } -} - #[deriving(Clone)] struct entry { val: T, @@ -205,11 +194,29 @@ fn encode_ty_type_param_defs(ebml_w: &mut writer::Encoder, } } +fn encode_region_param_defs(ebml_w: &mut writer::Encoder, + ecx: &EncodeContext, + params: @[ty::RegionParameterDef]) { + for param in params.iter() { + ebml_w.start_tag(tag_region_param_def); + + ebml_w.start_tag(tag_region_param_def_ident); + encode_name(ecx, ebml_w, param.ident); + ebml_w.end_tag(); + + ebml_w.wr_tagged_str(tag_region_param_def_def_id, + def_to_str(param.def_id)); + + ebml_w.end_tag(); + } +} + fn encode_bounds_and_type(ebml_w: &mut writer::Encoder, ecx: &EncodeContext, tpt: &ty::ty_param_bounds_and_ty) { encode_ty_type_param_defs(ebml_w, ecx, tpt.generics.type_param_defs, tag_items_data_item_ty_param_bounds); + encode_region_param_defs(ebml_w, ecx, tpt.generics.region_param_defs); encode_type(ecx, ebml_w, tpt.ty); } @@ -976,7 +983,6 @@ fn encode_info_for_item(ecx: &EncodeContext, encode_bounds_and_type(ebml_w, ecx, &lookup_item_type(tcx, def_id)); encode_name(ecx, ebml_w, item.ident); encode_path(ecx, ebml_w, path, ast_map::path_name(item.ident)); - encode_region_param(ecx, ebml_w, item); encode_visibility(ebml_w, vis); ebml_w.end_tag(); } @@ -994,7 +1000,6 @@ fn encode_info_for_item(ecx: &EncodeContext, } (ecx.encode_inlined_item)(ecx, ebml_w, path, ii_item(item)); encode_path(ecx, ebml_w, path, ast_map::path_name(item.ident)); - encode_region_param(ecx, ebml_w, item); // Encode inherent implementations for this enumeration. encode_inherent_implementations(ecx, ebml_w, def_id); @@ -1030,7 +1035,6 @@ fn encode_info_for_item(ecx: &EncodeContext, encode_name(ecx, ebml_w, item.ident); encode_attributes(ebml_w, item.attrs); encode_path(ecx, ebml_w, path, ast_map::path_name(item.ident)); - encode_region_param(ecx, ebml_w, item); encode_visibility(ebml_w, vis); /* Encode def_ids for each field and method @@ -1075,7 +1079,6 @@ fn encode_info_for_item(ecx: &EncodeContext, ebml_w.start_tag(tag_items_data_item); encode_def_id(ebml_w, def_id); encode_family(ebml_w, 'i'); - encode_region_param(ecx, ebml_w, item); encode_bounds_and_type(ebml_w, ecx, &lookup_item_type(tcx, def_id)); encode_name(ecx, ebml_w, item.ident); encode_attributes(ebml_w, item.attrs); @@ -1135,7 +1138,6 @@ fn encode_info_for_item(ecx: &EncodeContext, ebml_w.start_tag(tag_items_data_item); encode_def_id(ebml_w, def_id); encode_family(ebml_w, 'I'); - encode_region_param(ecx, ebml_w, item); let trait_def = ty::lookup_trait_def(tcx, def_id); encode_ty_type_param_defs(ebml_w, ecx, trait_def.generics.type_param_defs, diff --git a/src/librustc/metadata/tydecode.rs b/src/librustc/metadata/tydecode.rs index b365e7a48795e..1636205c76d62 100644 --- a/src/librustc/metadata/tydecode.rs +++ b/src/librustc/metadata/tydecode.rs @@ -48,7 +48,10 @@ pub enum DefIdSource { TypeWithId, // Identifies a type parameter (`fn foo() { ... }`). - TypeParameter + TypeParameter, + + // Identifies a region parameter (`fn foo<'X>() { ... }`). + RegionParameter, } type conv_did<'self> = &'self fn(source: DefIdSource, ast::DefId) -> ast::DefId; @@ -143,7 +146,7 @@ fn parse_path(st: &mut PState) -> @ast::Path { segments: idents.move_iter().map(|identifier| { ast::PathSegment { identifier: identifier, - lifetime: None, + lifetimes: opt_vec::Empty, types: opt_vec::Empty, } }).collect() @@ -165,7 +168,7 @@ fn parse_sigil(st: &mut PState) -> ast::Sigil { } } -fn parse_vstore(st: &mut PState) -> ty::vstore { +fn parse_vstore(st: &mut PState, conv: conv_did) -> ty::vstore { assert_eq!(next(st), '/'); let c = peek(st); @@ -178,22 +181,22 @@ fn parse_vstore(st: &mut PState) -> ty::vstore { match next(st) { '~' => ty::vstore_uniq, '@' => ty::vstore_box, - '&' => ty::vstore_slice(parse_region(st)), + '&' => ty::vstore_slice(parse_region(st, conv)), c => st.tcx.sess.bug(format!("parse_vstore(): bad input '{}'", c)) } } -fn parse_trait_store(st: &mut PState) -> ty::TraitStore { +fn parse_trait_store(st: &mut PState, conv: conv_did) -> ty::TraitStore { match next(st) { '~' => ty::UniqTraitStore, '@' => ty::BoxTraitStore, - '&' => ty::RegionTraitStore(parse_region(st)), + '&' => ty::RegionTraitStore(parse_region(st, conv)), c => st.tcx.sess.bug(format!("parse_trait_store(): bad input '{}'", c)) } } fn parse_substs(st: &mut PState, conv: conv_did) -> ty::substs { - let regions = parse_region_substs(st); + let regions = parse_region_substs(st, |x,y| conv(x,y)); let self_ty = parse_opt(st, |st| parse_ty(st, |x,y| conv(x,y)) ); @@ -209,13 +212,13 @@ fn parse_substs(st: &mut PState, conv: conv_did) -> ty::substs { }; } -fn parse_region_substs(st: &mut PState) -> ty::RegionSubsts { +fn parse_region_substs(st: &mut PState, conv: conv_did) -> ty::RegionSubsts { match next(st) { 'e' => ty::ErasedRegions, 'n' => { let mut regions = opt_vec::Empty; while peek(st) != '.' { - let r = parse_region(st); + let r = parse_region(st, |x,y| conv(x,y)); regions.push(r); } assert_eq!(next(st), '.'); @@ -225,34 +228,51 @@ fn parse_region_substs(st: &mut PState) -> ty::RegionSubsts { } } -fn parse_bound_region(st: &mut PState) -> ty::bound_region { +fn parse_bound_region(st: &mut PState, conv: conv_did) -> ty::bound_region { match next(st) { - 's' => ty::br_self, - 'a' => { - let id = parse_uint(st); - assert_eq!(next(st), '|'); - ty::br_anon(id) - } - '[' => ty::br_named(st.tcx.sess.ident_of(parse_str(st, ']'))), - 'c' => { - let id = parse_uint(st) as int; - assert_eq!(next(st), '|'); - ty::br_cap_avoid(id, @parse_bound_region(st)) - }, - _ => fail!("parse_bound_region: bad input") + 'a' => { + let id = parse_uint(st); + assert_eq!(next(st), '|'); + ty::br_anon(id) + } + '[' => { + let def = parse_def(st, RegionParameter, |x,y| conv(x,y)); + let ident = st.tcx.sess.ident_of(parse_str(st, ']')); + ty::br_named(def, ident) + } + 'f' => { + let id = parse_uint(st); + assert_eq!(next(st), '|'); + ty::br_fresh(id) + } + _ => fail!("parse_bound_region: bad input") } } -fn parse_region(st: &mut PState) -> ty::Region { +fn parse_region(st: &mut PState, conv: conv_did) -> ty::Region { match next(st) { 'b' => { - ty::re_bound(parse_bound_region(st)) + assert_eq!(next(st), '['); + let id = parse_uint(st) as int; + assert_eq!(next(st), '|'); + let br = parse_bound_region(st, |x,y| conv(x,y)); + assert_eq!(next(st), ']'); + ty::re_fn_bound(id, br) + } + 'B' => { + assert_eq!(next(st), '['); + let node_id = parse_uint(st) as int; + assert_eq!(next(st), '|'); + let index = parse_uint(st); + assert_eq!(next(st), '|'); + let nm = st.tcx.sess.ident_of(parse_str(st, ']')); + ty::re_type_bound(node_id, index, nm) } 'f' => { assert_eq!(next(st), '['); let id = parse_uint(st) as int; assert_eq!(next(st), '|'); - let br = parse_bound_region(st); + let br = parse_bound_region(st, |x,y| conv(x,y)); assert_eq!(next(st), ']'); ty::re_free(ty::FreeRegion {scope_id: id, bound_region: br}) @@ -331,14 +351,14 @@ fn parse_ty(st: &mut PState, conv: conv_did) -> ty::t { assert_eq!(next(st), '['); let def = parse_def(st, NominalType, |x,y| conv(x,y)); let substs = parse_substs(st, |x,y| conv(x,y)); - let store = parse_trait_store(st); + let store = parse_trait_store(st, |x,y| conv(x,y)); let mt = parse_mutability(st); let bounds = parse_bounds(st, |x,y| conv(x,y)); assert_eq!(next(st), ']'); return ty::mk_trait(st.tcx, def, substs, store, mt, bounds.builtin_bounds); } 'p' => { - let did = parse_def(st, TypeParameter, conv); + let did = parse_def(st, TypeParameter, |x,y| conv(x,y)); debug!("parsed ty_param: did={:?}", did); return ty::mk_param(st.tcx, parse_uint(st), did); } @@ -356,12 +376,12 @@ fn parse_ty(st: &mut PState, conv: conv_did) -> ty::t { } 'U' => return ty::mk_unboxed_vec(st.tcx, parse_mt(st, conv)), 'V' => { - let mt = parse_mt(st, conv); - let v = parse_vstore(st); + let mt = parse_mt(st, |x,y| conv(x,y)); + let v = parse_vstore(st, |x,y| conv(x,y)); return ty::mk_evec(st.tcx, mt, v); } 'v' => { - let v = parse_vstore(st); + let v = parse_vstore(st, |x,y| conv(x,y)); return ty::mk_estr(st.tcx, v); } 'T' => { @@ -495,7 +515,7 @@ fn parse_closure_ty(st: &mut PState, conv: conv_did) -> ty::ClosureTy { let sigil = parse_sigil(st); let purity = parse_purity(next(st)); let onceness = parse_onceness(next(st)); - let region = parse_region(st); + let region = parse_region(st, |x,y| conv(x,y)); let bounds = parse_bounds(st, |x,y| conv(x,y)); let sig = parse_sig(st, |x,y| conv(x,y)); ty::ClosureTy { @@ -511,7 +531,7 @@ fn parse_closure_ty(st: &mut PState, conv: conv_did) -> ty::ClosureTy { fn parse_bare_fn_ty(st: &mut PState, conv: conv_did) -> ty::BareFnTy { let purity = parse_purity(next(st)); let abi = parse_abi_set(st); - let sig = parse_sig(st, conv); + let sig = parse_sig(st, |x,y| conv(x,y)); ty::BareFnTy { purity: purity, abis: abi, @@ -521,22 +541,22 @@ fn parse_bare_fn_ty(st: &mut PState, conv: conv_did) -> ty::BareFnTy { fn parse_sig(st: &mut PState, conv: conv_did) -> ty::FnSig { assert_eq!(next(st), '['); + let id = parse_uint(st) as int; + assert_eq!(next(st), '|'); let mut inputs = ~[]; while peek(st) != ']' { inputs.push(parse_ty(st, |x,y| conv(x,y))); } st.pos += 1u; // eat the ']' - let variadic = if peek(st) == 'A' { - st.pos += 1; // eat the 'A' - true - } else { false }; - let ret_ty = parse_ty(st, conv); - ty::FnSig { - bound_lifetime_names: opt_vec::Empty, // FIXME(#4846) - inputs: inputs, - output: ret_ty, - variadic: variadic - } + let variadic = match next(st) { + 'V' => true, + 'N' => false, + }; + let ret_ty = parse_ty(st, |x,y| conv(x,y)); + ty::FnSig {binder_id: id, + inputs: inputs, + output: ret_ty, + variadic: variadic} } // Rust metadata parsing diff --git a/src/librustc/metadata/tyencode.rs b/src/librustc/metadata/tyencode.rs index 5397bf0e768d8..af28162dbfd5d 100644 --- a/src/librustc/metadata/tyencode.rs +++ b/src/librustc/metadata/tyencode.rs @@ -155,18 +155,31 @@ fn enc_region_substs(w: @mut MemWriter, cx: @ctxt, substs: &ty::RegionSubsts) { fn enc_region(w: @mut MemWriter, cx: @ctxt, r: ty::Region) { match r { - ty::re_bound(br) => { - mywrite!(w, "b"); + ty::re_fn_bound(id, br) => { + mywrite!(w, "b[{}|", id); enc_bound_region(w, cx, br); + mywrite!(w, "]"); + } + ty::re_type_bound(node_id, index, ident) => { + mywrite!(w, "B[{}|{}|{}]", + node_id, + index, + cx.tcx.sess.str_of(ident)); } ty::re_free(ref fr) => { mywrite!(w, "f[{}|", fr.scope_id); enc_bound_region(w, cx, fr.bound_region); mywrite!(w, "]"); } - ty::re_scope(nid) => mywrite!(w, "s{}|", nid), - ty::re_static => mywrite!(w, "t"), - ty::re_empty => mywrite!(w, "e"), + ty::re_scope(nid) => { + mywrite!(w, "s{}|", nid); + } + ty::re_static => { + mywrite!(w, "t"); + } + ty::re_empty => { + mywrite!(w, "e"); + } ty::re_infer(_) => { // these should not crop up after typeck cx.diag.handler().bug("Cannot encode region variables"); @@ -176,14 +189,17 @@ fn enc_region(w: @mut MemWriter, cx: @ctxt, r: ty::Region) { fn enc_bound_region(w: @mut MemWriter, cx: @ctxt, br: ty::bound_region) { match br { - ty::br_self => mywrite!(w, "s"), - ty::br_anon(idx) => mywrite!(w, "a{}|", idx), - ty::br_named(s) => mywrite!(w, "[{}]", cx.tcx.sess.str_of(s)), - ty::br_cap_avoid(id, br) => { - mywrite!(w, "c{}|", id); - enc_bound_region(w, cx, *br); - } - ty::br_fresh(id) => mywrite!(w, "{}", id), + ty::br_anon(idx) => { + mywrite!(w, "a{}|", idx); + } + ty::br_named(d, s) => { + mywrite!(w, "[{}|{}]", + (cx.ds)(d), + cx.tcx.sess.str_of(s)); + } + ty::br_fresh(id) => { + mywrite!(w, "f{}|", id); + } } } @@ -366,13 +382,15 @@ fn enc_closure_ty(w: @mut MemWriter, cx: @ctxt, ft: &ty::ClosureTy) { } fn enc_fn_sig(w: @mut MemWriter, cx: @ctxt, fsig: &ty::FnSig) { - mywrite!(w, "["); + mywrite!(w, "[{}|", fsig.binder_id); for ty in fsig.inputs.iter() { enc_ty(w, cx, *ty); } mywrite!(w, "]"); if fsig.variadic { - mywrite!(w, "A"); + mywrite!(w, "V"); + } else { + mywrite!(w, "N"); } enc_ty(w, cx, fsig.output); } diff --git a/src/librustc/middle/astencode.rs b/src/librustc/middle/astencode.rs index cb8c7b3262fbf..e60b9382be49a 100644 --- a/src/librustc/middle/astencode.rs +++ b/src/librustc/middle/astencode.rs @@ -15,7 +15,8 @@ use driver::session::Session; use e = metadata::encoder; use metadata::decoder; use metadata::tydecode; -use metadata::tydecode::{DefIdSource, NominalType, TypeWithId, TypeParameter}; +use metadata::tydecode::{DefIdSource, NominalType, TypeWithId, TypeParameter, + RegionParameter}; use metadata::tyencode; use middle::freevars::freevar_entry; use middle::typeck::{method_origin, method_map_entry}; @@ -234,6 +235,12 @@ impl tr for ast::DefId { } } +impl tr for Option { + fn tr(&self, xcx: @ExtendedDecodeContext) -> Option { + self.map(|d| xcx.tr_def_id(d)) + } +} + impl tr for Span { fn tr(&self, xcx: @ExtendedDecodeContext) -> Span { xcx.tr_span(*self) @@ -469,7 +476,11 @@ impl tr for ty::AutoRef { impl tr for ty::Region { fn tr(&self, xcx: @ExtendedDecodeContext) -> ty::Region { match *self { - ty::re_bound(br) => ty::re_bound(br.tr(xcx)), + ty::re_fn_bound(id, br) => ty::re_fn_bound(xcx.tr_id(id), + br.tr(xcx)), + ty::re_type_bound(id, index, ident) => ty::re_type_bound(xcx.tr_id(id), + index, + ident), ty::re_scope(id) => ty::re_scope(xcx.tr_id(id)), ty::re_empty | ty::re_static | ty::re_infer(*) => *self, ty::re_free(ref fr) => { @@ -483,10 +494,10 @@ impl tr for ty::Region { impl tr for ty::bound_region { fn tr(&self, xcx: @ExtendedDecodeContext) -> ty::bound_region { match *self { - ty::br_anon(_) | ty::br_named(_) | ty::br_self | + ty::br_anon(_) | ty::br_fresh(_) => *self, - ty::br_cap_avoid(id, br) => ty::br_cap_avoid(xcx.tr_id(id), - @br.tr(xcx)) + ty::br_named(id, ident) => ty::br_named(xcx.tr_def_id(id), + ident), } } } @@ -821,8 +832,8 @@ impl ebml_writer_helpers for writer::Encoder { this.emit_type_param_def(ecx, type_param_def); } } - do this.emit_struct_field("region_param", 1) |this| { - tpbt.generics.region_param.encode(this); + do this.emit_struct_field("region_param_defs", 1) |this| { + tpbt.generics.region_param_defs.encode(this); } } } @@ -1086,6 +1097,8 @@ impl ebml_decoder_decoder_helpers for reader::Decoder { // are not used during trans. return do self.read_opaque |this, doc| { + debug!("read_ty({})", type_string(doc)); + let ty = tydecode::parse_ty_data( *doc.data, xcx.dcx.cdata.cnum, @@ -1093,10 +1106,6 @@ impl ebml_decoder_decoder_helpers for reader::Decoder { xcx.dcx.tcx, |s, a| this.convert_def_id(xcx, s, a)); - debug!("read_ty({}) = {}", - type_string(doc), - ty_to_str(xcx.dcx.tcx, ty)); - ty }; @@ -1139,8 +1148,8 @@ impl ebml_decoder_decoder_helpers for reader::Decoder { @this.read_to_vec(|this| this.read_type_param_def(xcx)) }), - region_param: - this.read_struct_field("region_param", + region_param_defs: + this.read_struct_field("region_param_defs", 1, |this| { Decodable::decode(this) @@ -1161,7 +1170,6 @@ impl ebml_decoder_decoder_helpers for reader::Decoder { did: ast::DefId) -> ast::DefId { /*! - * * Converts a def-id that appears in a type. The correct * translation will depend on what kind of def-id this is. * This is a subtle point: type definitions are not @@ -1172,10 +1180,25 @@ impl ebml_decoder_decoder_helpers for reader::Decoder { * However, *type parameters* are cloned along with the function * they are attached to. So we should translate those def-ids * to refer to the new, cloned copy of the type parameter. + * We only see references to free type parameters in the body of + * an inlined function. In such cases, we need the def-id to + * be a local id so that the TypeContents code is able to lookup + * the relevant info in the ty_param_defs table. + * + * *Region parameters*, unfortunately, are another kettle of fish. + * In such cases, def_id's can appear in types to distinguish + * shadowed bound regions and so forth. It doesn't actually + * matter so much what we do to these, since regions are erased + * at trans time, but it's good to keep them consistent just in + * case. We translate them with `tr_def_id()` which will map + * the crate numbers back to the original source crate. + * + * It'd be really nice to refactor the type repr to not include + * def-ids so that all these distinctions were unnecessary. */ let r = match source { - NominalType | TypeWithId => xcx.tr_def_id(did), + NominalType | TypeWithId | RegionParameter => xcx.tr_def_id(did), TypeParameter => xcx.tr_intern_def_id(did) }; debug!("convert_def_id(source={:?}, did={:?})={:?}", source, did, r); diff --git a/src/librustc/middle/borrowck/gather_loans/mod.rs b/src/librustc/middle/borrowck/gather_loans/mod.rs index dd161b189da27..729da749ec691 100644 --- a/src/librustc/middle/borrowck/gather_loans/mod.rs +++ b/src/librustc/middle/borrowck/gather_loans/mod.rs @@ -486,7 +486,8 @@ impl<'self> GatherLoanCtxt<'self> { } ty::re_empty | - ty::re_bound(*) | + ty::re_fn_bound(*) | + ty::re_type_bound(*) | ty::re_infer(*) => { self.tcx().sess.span_bug( cmt.span, diff --git a/src/librustc/middle/kind.rs b/src/librustc/middle/kind.rs index fd5114889fddb..99f2d7a87002f 100644 --- a/src/librustc/middle/kind.rs +++ b/src/librustc/middle/kind.rs @@ -540,7 +540,7 @@ pub fn check_cast_for_escaping_regions( target_regions.push(r); } }, - |_| true); + |_| ()); // Check, based on the region associated with the trait, whether it can // possibly escape the enclosing fn item (note that all type parameters @@ -582,7 +582,6 @@ pub fn check_cast_for_escaping_regions( } _ => {} } - true }); fn is_re_scope(r: ty::Region) -> bool { diff --git a/src/librustc/middle/privacy.rs b/src/librustc/middle/privacy.rs index 70aa05848f366..eeedd25adac28 100644 --- a/src/librustc/middle/privacy.rs +++ b/src/librustc/middle/privacy.rs @@ -781,7 +781,7 @@ impl<'self> Visitor<()> for PrivacyVisitor<'self> { debug!("privacy - list {}", pid.node.id); let seg = ast::PathSegment { identifier: pid.node.name, - lifetime: None, + lifetimes: opt_vec::Empty, types: opt_vec::Empty, }; let segs = ~[seg]; diff --git a/src/librustc/middle/resolve.rs b/src/librustc/middle/resolve.rs index 9f848b4c2276c..23fef5e351674 100644 --- a/src/librustc/middle/resolve.rs +++ b/src/librustc/middle/resolve.rs @@ -4182,7 +4182,7 @@ impl Resolver { if path.segments .iter() - .any(|s| s.lifetime.is_some()) { + .any(|s| !s.lifetimes.is_empty()) { self.session.span_err(path.span, "lifetime parameters \ are not allowed on \ diff --git a/src/librustc/middle/subst.rs b/src/librustc/middle/subst.rs index a13248f2480d1..7654a46ec3639 100644 --- a/src/librustc/middle/subst.rs +++ b/src/librustc/middle/subst.rs @@ -173,35 +173,30 @@ impl Subst for ty::Generics { fn subst(&self, tcx: ty::ctxt, substs: &ty::substs) -> ty::Generics { ty::Generics { type_param_defs: self.type_param_defs.subst(tcx, substs), - region_param: self.region_param + region_param_defs: self.region_param_defs.subst(tcx, substs), } } } +impl Subst for ty::RegionParameterDef { + fn subst(&self, _: ty::ctxt, _: &ty::substs) -> ty::RegionParameterDef { + *self + } +} + impl Subst for ty::Region { - fn subst(&self, tcx: ty::ctxt, substs: &ty::substs) -> ty::Region { - // Note: This routine only handles the self region, because it - // is only concerned with substitutions of regions that appear - // in types. Region substitution of the bound regions that - // appear in a function signature is done using the - // specialized routine + fn subst(&self, _tcx: ty::ctxt, substs: &ty::substs) -> ty::Region { + // Note: This routine only handles regions that are bound on + // type declarationss and other outer declarations, not those + // bound in *fn types*. Region substitution of the bound + // regions that appear in a function signature is done using + // the specialized routine // `middle::typeck::check::regionmanip::replace_bound_regions_in_fn_sig()`. - // As we transition to the new region syntax this distinction - // will most likely disappear. match self { - &ty::re_bound(ty::br_self) => { + &ty::re_type_bound(_, i, _) => { match substs.regions { ty::ErasedRegions => ty::re_static, - ty::NonerasedRegions(ref regions) => { - if regions.len() != 1 { - tcx.sess.bug( - format!("ty::Region\\#subst(): \ - Reference to self region when \ - given substs with no self region: {}", - substs.repr(tcx))); - } - *regions.get(0) - } + ty::NonerasedRegions(ref regions) => *regions.get(i), } } _ => *self diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index 9d6ad4d8bf694..66fba347acc13 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -436,14 +436,17 @@ pub struct ClosureTy { * Signature of a function type, which I have arbitrarily * decided to use to refer to the input/output types. * - * - `lifetimes` is the list of region names bound in this fn. + * - `binder_id` is the node id where this fn type appeared; + * it is used to identify all the bound regions appearing + * in the input/output types that are bound by this fn type + * (vs some enclosing or enclosed fn type) * - `inputs` is the list of arguments and their modes. * - `output` is the return type. * - `variadic` indicates whether this is a varidic function. (only true for foreign fns) */ #[deriving(Clone, Eq, IterBytes)] pub struct FnSig { - bound_lifetime_names: OptVec, + binder_id: ast::NodeId, inputs: ~[t], output: t, variadic: bool @@ -458,16 +461,13 @@ pub struct param_ty { /// Representation of regions: #[deriving(Clone, Eq, IterBytes, Encodable, Decodable, ToStr)] pub enum Region { - /// Bound regions are found (primarily) in function types. They indicate - /// region parameters that have yet to be replaced with actual regions - /// (analogous to type parameters, except that due to the monomorphic - /// nature of our type system, bound type parameters are always replaced - /// with fresh type variables whenever an item is referenced, so type - /// parameters only appear "free" in types. Regions in contrast can - /// appear free or bound.). When a function is called, all bound regions - /// tied to that function's node-id are replaced with fresh region - /// variables whose value is then inferred. - re_bound(bound_region), + // Region bound in a type declaration (type/enum/struct/trait), + // which will be substituted when an instance of the type is accessed + re_type_bound(/* param id */ ast::NodeId, /*index*/ uint, ast::Ident), + + // Region bound in a fn scope, which will be substituted when the + // fn is called. + re_fn_bound(/* binder_id */ ast::NodeId, bound_region), /// When checking a function body, the types of all arguments and so forth /// that refer to bound region parameters are modified to refer to free @@ -496,42 +496,32 @@ pub enum Region { impl Region { pub fn is_bound(&self) -> bool { match self { - &re_bound(*) => true, + &ty::re_type_bound(*) => true, + &ty::re_fn_bound(*) => true, _ => false } } } -#[deriving(Clone, Eq, IterBytes, Encodable, Decodable, ToStr)] +#[deriving(Clone, Eq, TotalOrd, TotalEq, IterBytes, Encodable, Decodable, ToStr)] pub struct FreeRegion { scope_id: NodeId, bound_region: bound_region } -#[deriving(Clone, Eq, IterBytes, Encodable, Decodable, ToStr)] +#[deriving(Clone, Eq, TotalEq, TotalOrd, IterBytes, Encodable, Decodable, ToStr)] pub enum bound_region { - /// The self region for structs, impls (&T in a type defn or &'self T) - br_self, - /// An anonymous region parameter for a given fn (&T) br_anon(uint), /// Named region parameters for functions (a in &'a T) - br_named(ast::Ident), + /// + /// The def-id is needed to distinguish free regions in + /// the event of shadowing. + br_named(ast::DefId, ast::Ident), /// Fresh bound identifiers created during GLB computations. br_fresh(uint), - - /** - * Handles capture-avoiding substitution in a rather subtle case. If you - * have a closure whose argument types are being inferred based on the - * expected type, and the expected type includes bound regions, then we - * will wrap those bound regions in a br_cap_avoid() with the id of the - * fn expression. This ensures that the names are not "captured" by the - * enclosing scope, which may define the same names. For an example of - * where this comes up, see src/test/compile-fail/regions-ret-borrowed.rs - * and regions-ret-borrowed-1.rs. */ - br_cap_avoid(ast::NodeId, @bound_region), } /** @@ -868,12 +858,21 @@ pub struct TypeParameterDef { bounds: @ParamBounds } -/// Information about the type/lifetime parametesr associated with an item. +#[deriving(Encodable, Decodable, Clone)] +pub struct RegionParameterDef { + ident: ast::Ident, + def_id: ast::DefId, +} + +/// Information about the type/lifetime parameters associated with an item. /// Analogous to ast::Generics. #[deriving(Clone)] pub struct Generics { + /// List of type parameters declared on the item. type_param_defs: @~[TypeParameterDef], - region_param: Option, + + /// List of region parameters declared on the item. + region_param_defs: @[RegionParameterDef], } impl Generics { @@ -882,6 +881,33 @@ impl Generics { } } +/// When type checking, we use the `ParameterEnvironment` to track +/// details about the type/lifetime parameters that are in scope. +/// It primarily stores the bounds information. +/// +/// Note: This information might seem to be redundant with the data in +/// `tcx.ty_param_defs`, but it is not. That table contains the +/// parameter definitions from an "outside" perspective, but this +/// struct will contain the bounds for a parameter as seen from inside +/// the function body. Currently the only real distinction is that +/// bound lifetime parameters are replaced with free ones, but in the +/// future I hope to refine the representation of types so as to make +/// more distinctions clearer. +pub struct ParameterEnvironment { + /// A substitution that can be applied to move from + /// the "outer" view of a type or method to the "inner" view. + /// In general, this means converting from bound parameters to + /// free parameters. Since we currently represent bound/free type + /// parameters in the same way, this only has an affect on regions. + free_substs: ty::substs, + + /// Bound on the Self parameter + self_param_bound: Option<@TraitRef>, + + /// Bounds on each numbered type parameter + type_param_bounds: ~[ParamBounds], +} + /// A polytype. /// /// - `bounds`: The list of bounds for each type parameter. The length of the @@ -1255,14 +1281,17 @@ pub fn mk_bare_fn(cx: ctxt, fty: BareFnTy) -> t { mk_t(cx, ty_bare_fn(fty)) } -pub fn mk_ctor_fn(cx: ctxt, input_tys: &[ty::t], output: ty::t) -> t { +pub fn mk_ctor_fn(cx: ctxt, + binder_id: ast::NodeId, + input_tys: &[ty::t], + output: ty::t) -> t { let input_args = input_tys.map(|t| *t); mk_bare_fn(cx, BareFnTy { purity: ast::impure_fn, abis: AbiSet::Rust(), sig: FnSig { - bound_lifetime_names: opt_vec::Empty, + binder_id: binder_id, inputs: input_args, output: output, variadic: false @@ -4662,3 +4691,79 @@ pub fn hash_crate_independent(tcx: ctxt, t: t, local_hash: @str) -> u64 { hash.result_u64() } + +pub fn construct_parameter_environment( + tcx: ctxt, + self_bound: Option<@TraitRef>, + item_type_params: &[TypeParameterDef], + method_type_params: &[TypeParameterDef], + item_region_params: &[RegionParameterDef], + free_id: ast::NodeId) + -> ParameterEnvironment +{ + /*! See `ParameterEnvironment` struct def'n for details */ + + // + // Construct the free substs. + // + + // map Self => Self + let self_ty = self_bound.map(|t| ty::mk_self(tcx, t.def_id)); + + // map A => A + let num_item_type_params = item_type_params.len(); + let num_method_type_params = method_type_params.len(); + let num_type_params = num_item_type_params + num_method_type_params; + let type_params = vec::from_fn(num_type_params, |i| { + let def_id = if i < num_item_type_params { + item_type_params[i].def_id + } else { + method_type_params[i - num_item_type_params].def_id + }; + + ty::mk_param(tcx, i, def_id) + }); + + // map bound 'a => free 'a + let region_params = item_region_params.iter(). + map(|r| ty::re_free(ty::FreeRegion { + scope_id: free_id, + bound_region: ty::br_named(r.def_id, r.ident)})). + collect(); + + let free_substs = substs { + self_ty: self_ty, + tps: type_params, + regions: ty::NonerasedRegions(region_params) + }; + + // + // Compute the bounds on Self and the type parameters. + // + + let self_bound_substd = self_bound.map(|b| b.subst(tcx, &free_substs)); + let type_param_bounds_substd = vec::from_fn(num_type_params, |i| { + if i < num_item_type_params { + (*item_type_params[i].bounds).subst(tcx, &free_substs) + } else { + let j = i - num_item_type_params; + (*method_type_params[j].bounds).subst(tcx, &free_substs) + } + }); + + ty::ParameterEnvironment { + free_substs: free_substs, + self_param_bound: self_bound_substd, + type_param_bounds: type_param_bounds_substd, + } +} + +impl substs { + pub fn empty() -> substs { + substs { + self_ty: None, + tps: ~[], + regions: NonerasedRegions(opt_vec::Empty) + } + } +} diff --git a/src/librustc/middle/typeck/astconv.rs b/src/librustc/middle/typeck/astconv.rs index 11d995762ee72..0c0abaa5d76cf 100644 --- a/src/librustc/middle/typeck/astconv.rs +++ b/src/librustc/middle/typeck/astconv.rs @@ -154,13 +154,11 @@ pub fn opt_ast_region_to_region( fn ast_path_substs( this: &AC, rscope: &RS, - def_id: ast::DefId, decl_generics: &ty::Generics, self_ty: Option, path: &ast::Path) -> ty::substs { /*! - * * Given a path `path` that refers to an item `I` with the * declared generics `decl_generics`, returns an appropriate * set of substitutions for this particular reference to `I`. @@ -171,30 +169,28 @@ fn ast_path_substs( // If the type is parameterized by the this region, then replace this // region with the current anon region binding (in other words, // whatever & would get replaced with). - let regions = match (&decl_generics.region_param, - &path.segments.last().lifetime) { - (&None, &None) => { - opt_vec::Empty - } - (&None, &Some(_)) => { + let expected_num_region_params = decl_generics.region_param_defs.len(); + let supplied_num_region_params = path.segments.last().lifetimes.len(); + let regions = if expected_num_region_params == supplied_num_region_params { + path.segments.last().lifetimes.map( + |l| ast_region_to_region(this.tcx(), l)) + } else { + let anon_regions = + rscope.anon_regions(path.span, expected_num_region_params); + + if supplied_num_region_params != 0 || anon_regions.is_none() { tcx.sess.span_err( path.span, - format!("no region bound is allowed on `{}`, \ - which is not declared as containing region pointers", - ty::item_path_str(tcx, def_id))); - opt_vec::Empty - } - (&Some(_), &None) => { - let res = rscope.anon_region(path.span); - let r = get_region_reporting_err(this.tcx(), path.span, &None, res); - opt_vec::with(r) + format!("wrong number of lifetime parameters: \ + expected {} but found {}", + expected_num_region_params, + supplied_num_region_params)); } - (&Some(_), &Some(_)) => { - opt_vec::with( - ast_region_to_region(this, - rscope, - path.span, - &path.segments.last().lifetime)) + + match anon_regions { + Some(v) => opt_vec::from(v), + None => opt_vec::from(vec::from_fn(expected_num_region_params, + |_| ty::re_static)) // hokey } }; @@ -234,7 +230,7 @@ pub fn ast_path_to_substs_and_ty( ast_path_substs( this, rscope, - trait_def.trait_ref.def_id, &trait_def.generics, self_ty, path); @@ -304,6 +299,7 @@ pub fn ast_ty_to_ty( constr: &fn(ty::mt) -> ty::t) -> ty::t { let tcx = this.tcx(); + debug!("mk_pointer(vst={:?})", vst); match a_seq_ty.ty.node { ast::ty_vec(ref mt) => { @@ -311,6 +307,7 @@ pub fn ast_ty_to_ty( if a_seq_ty.mutbl == ast::MutMutable { mt = ty::mt { ty: mt.ty, mutbl: a_seq_ty.mutbl }; } + debug!("&[]: vst={:?}", vst); return ty::mk_evec(tcx, mt, vst); } ast::ty_path(ref path, ref bounds, id) => { @@ -369,7 +366,7 @@ pub fn ast_ty_to_ty( } if (flags & NO_REGIONS) != 0u { - if path.segments.last().lifetime.is_some() { + if !path.segments.last().lifetimes.is_empty() { tcx.sess.span_err( path.span, "region parameters are not allowed on this type"); @@ -422,8 +419,8 @@ pub fn ast_ty_to_ty( if bf.decl.variadic && !bf.abis.is_c() { tcx.sess.span_err(ast_ty.span, "variadic function must have C calling convention"); } - ty::mk_bare_fn(tcx, ty_of_bare_fn(this, rscope, bf.purity, - bf.abis, &bf.lifetimes, &bf.decl)) + ty::mk_bare_fn(tcx, ty_of_bare_fn(this, ast_ty.id, bf.purity, + bf.abis, &bf.decl)) } ast::ty_closure(ref f) => { if f.sigil == ast::ManagedSigil { @@ -440,6 +437,7 @@ pub fn ast_ty_to_ty( }); let fn_decl = ty_of_closure(this, rscope, + ast_ty.id, f.sigil, f.purity, f.onceness, @@ -447,7 +445,6 @@ pub fn ast_ty_to_ty( &f.region, &f.decl, None, - &f.lifetimes, ast_ty.span); ty::mk_closure(tcx, fn_decl) } @@ -594,9 +591,8 @@ struct SelfInfo { pub fn ty_of_method( this: &AC, - rscope: &RS, + id: ast::NodeId, purity: ast::purity, - lifetimes: &OptVec, untransformed_self_ty: ty::t, explicit_self: ast::explicit_self, decl: &ast::fn_decl) -> (Option, ty::BareFnTy) @@ -606,33 +602,31 @@ pub fn ty_of_method( explicit_self: explicit_self }; let (a, b) = ty_of_method_or_bare_fn( - this, rscope, purity, AbiSet::Rust(), lifetimes, Some(&self_info), decl); + this, id, purity, AbiSet::Rust(), Some(&self_info), decl); (a.unwrap(), b) } -pub fn ty_of_bare_fn( +pub fn ty_of_bare_fn( this: &AC, - rscope: &RS, + id: ast::NodeId, purity: ast::purity, abi: AbiSet, - lifetimes: &OptVec, decl: &ast::fn_decl) -> ty::BareFnTy { - let (_, b) = ty_of_method_or_bare_fn( - this, rscope, purity, abi, lifetimes, None, decl); + let (_, b) = ty_of_method_or_bare_fn(this, id, purity, + abi, None, decl); b } -fn ty_of_method_or_bare_fn( +fn ty_of_method_or_bare_fn( this: &AC, - rscope: &RS, + id: ast::NodeId, purity: ast::purity, abi: AbiSet, - lifetimes: &OptVec, opt_self_info: Option<&SelfInfo>, decl: &ast::fn_decl) -> (Option>, ty::BareFnTy) { - debug!("ty_of_bare_fn"); + debug!("ty_of_method_or_bare_fn"); // new region names that appear inside of the fn decl are bound to // that function type @@ -653,12 +647,10 @@ fn ty_of_method_or_bare_fn( ty::BareFnTy { purity: purity, abis: abi, - sig: ty::FnSig { - bound_lifetime_names: bound_lifetime_names, - inputs: input_tys, - output: output_ty, - variadic: decl.variadic - } + sig: ty::FnSig {binder_id: id, + inputs: input_tys, + output: output_ty, + variadic: decl.variadic} }); fn transform_self_ty( @@ -697,6 +689,7 @@ fn ty_of_method_or_bare_fn( pub fn ty_of_closure( this: &AC, rscope: &RS, + id: ast::NodeId, sigil: ast::Sigil, purity: ast::purity, onceness: ast::Onceness, @@ -704,17 +697,10 @@ pub fn ty_of_closure( opt_lifetime: &Option, decl: &ast::fn_decl, expected_sig: Option, - lifetimes: &OptVec, span: Span) -> ty::ClosureTy { - // The caller should not both provide explicit bound lifetime - // names and expected types. Either we infer the bound lifetime - // names or they are provided, but not both. - assert!(lifetimes.is_empty() || expected_sig.is_none()); - debug!("ty_of_fn_decl"); - let _i = indenter(); // resolve the function bound region in the original region // scope `rscope`, not the scope of the function parameters @@ -763,12 +749,10 @@ pub fn ty_of_closure( onceness: onceness, region: bound_region, bounds: bounds, - sig: ty::FnSig { - bound_lifetime_names: bound_lifetime_names, - inputs: input_tys, - output: output_ty, - variadic: decl.variadic - } + sig: ty::FnSig {binder_id: id, + inputs: input_tys, + output: output_ty, + variadic: decl.variadic} } } diff --git a/src/librustc/middle/typeck/check/method.rs b/src/librustc/middle/typeck/check/method.rs index af1d5ce3cc608..870b29882fd6e 100644 --- a/src/librustc/middle/typeck/check/method.rs +++ b/src/librustc/middle/typeck/check/method.rs @@ -85,7 +85,6 @@ use middle::ty::*; use middle::ty; use middle::typeck::check::{FnCtxt, impl_self_ty}; use middle::typeck::check::{structurally_resolved_type}; -use middle::typeck::check::vtable::VtableContext; use middle::typeck::check::vtable; use middle::typeck::check; use middle::typeck::infer; @@ -99,7 +98,6 @@ use util::ppaux::Repr; use std::hashmap::HashSet; use std::result; use std::vec; -use extra::list::Nil; use syntax::ast::{DefId, sty_value, sty_region, sty_box}; use syntax::ast::{sty_uniq, sty_static, NodeId}; use syntax::ast::{MutMutable, MutImmutable}; @@ -265,8 +263,7 @@ impl<'self> LookupContext<'self> { self.search_for_autosliced_method(self_ty, autoderefs) } - fn deref(&self, ty: ty::t) - -> Option { + fn deref(&self, ty: ty::t) -> Option { match ty::deref(self.tcx(), ty, false) { None => None, Some(t) => { @@ -327,11 +324,10 @@ impl<'self> LookupContext<'self> { ty_param(p) => { self.push_inherent_candidates_from_param(self_ty, p); } - ty_self(self_did) => { + ty_self(*) => { // Call is of the form "self.foo()" and appears in one // of a trait's default method implementations. - self.push_inherent_candidates_from_self( - self_ty, self_did); + self.push_inherent_candidates_from_self(self_ty); } _ => { /* No bound methods in these types */ } } @@ -448,32 +444,20 @@ impl<'self> LookupContext<'self> { param_ty: param_ty) { debug!("push_inherent_candidates_from_param(param_ty={:?})", param_ty); - let _indenter = indenter(); - - let tcx = self.tcx(); - let type_param_def = match tcx.ty_param_defs.find(¶m_ty.def_id.node) { - Some(t) => t, - None => { - tcx.sess.span_bug( - self.expr.span, - format!("No param def for {:?}", param_ty)); - } - }; - self.push_inherent_candidates_from_bounds( - rcvr_ty, type_param_def.bounds.trait_bounds, + rcvr_ty, + self.fcx.inh.param_env.type_param_bounds[param_ty.idx].trait_bounds, param_numbered(param_ty.idx)); } fn push_inherent_candidates_from_self(&self, - self_ty: ty::t, - did: DefId) { - let tcx = self.tcx(); - - let trait_ref = ty::lookup_trait_def(tcx, did).trait_ref; + rcvr_ty: ty::t) { + debug!("push_inherent_candidates_from_self()"); self.push_inherent_candidates_from_bounds( - self_ty, &[trait_ref], param_self); + rcvr_ty, + [self.fcx.inh.param_env.self_param_bound.unwrap()], + param_self) } fn push_inherent_candidates_from_bounds(&self, @@ -574,10 +558,7 @@ impl<'self> LookupContext<'self> { // determine the `self` of the impl with fresh // variables for each parameter: let location_info = &vtable::location_info_for_expr(self.self_expr); - let vcx = VtableContext { - ccx: self.fcx.ccx, - infcx: self.fcx.infcx() - }; + let vcx = self.fcx.vtable_context(); let ty::ty_param_substs_and_ty { substs: impl_substs, ty: impl_ty @@ -1010,7 +991,7 @@ impl<'self> LookupContext<'self> { }; let (_, opt_transformed_self_ty, fn_sig) = replace_bound_regions_in_fn_sig( - tcx, @Nil, Some(transformed_self_ty), &bare_fn_ty.sig, + tcx, Some(transformed_self_ty), &bare_fn_ty.sig, |br| self.fcx.infcx().next_region_var( infer::BoundRegionInFnCall(self.expr.span, br))); let transformed_self_ty = opt_transformed_self_ty.unwrap(); diff --git a/src/librustc/middle/typeck/check/mod.rs b/src/librustc/middle/typeck/check/mod.rs index 32284584b6583..982bc49341767 100644 --- a/src/librustc/middle/typeck/check/mod.rs +++ b/src/librustc/middle/typeck/check/mod.rs @@ -81,10 +81,12 @@ use middle::const_eval; use middle::pat_util::pat_id_map; use middle::pat_util; use middle::lint::unreachable_code; +use middle::subst::Subst; use middle::ty::{FnSig, VariantInfo}; use middle::ty::{ty_param_bounds_and_ty, ty_param_substs_and_ty}; use middle::ty::{substs, param_ty, Disr, ExprTyProvider}; use middle::ty; +use middle::ty_fold::TypeFolder; use middle::typeck::astconv::AstConv; use middle::typeck::astconv::{ast_region_to_region, ast_ty_to_ty}; use middle::typeck::astconv; @@ -99,22 +101,18 @@ use middle::typeck::check::vtable::{LocationInfo, VtableContext}; use middle::typeck::CrateCtxt; use middle::typeck::infer::{resolve_type, force_tvar}; use middle::typeck::infer; -use middle::typeck::rscope::bound_self_region; -use middle::typeck::rscope::{RegionError}; use middle::typeck::rscope::RegionScope; -use middle::typeck::{isr_alist, lookup_def_ccx}; +use middle::typeck::{lookup_def_ccx}; use middle::typeck::no_params; use middle::typeck::{require_same_types, method_map, vtable_map}; use util::common::{block_query, indenter, loop_query}; -use util::ppaux::{bound_region_ptr_to_str}; +use util::ppaux::UserString; use util::ppaux; - use std::hashmap::HashMap; use std::result; use std::util::replace; use std::vec; -use extra::list::Nil; use syntax::abi::AbiSet; use syntax::ast::{provided, required}; use syntax::ast; @@ -127,7 +125,6 @@ use syntax::codemap; use syntax::opt_vec::OptVec; use syntax::opt_vec; use syntax::parse::token; -use syntax::parse::token::special_idents; use syntax::print::pprust; use syntax::visit; use syntax::visit::Visitor; @@ -157,9 +154,10 @@ pub struct SelfInfo { /// Here, the function `foo()` and the closure passed to /// `bar()` will each have their own `FnCtxt`, but they will /// share the inherited fields. -pub struct inherited { +pub struct Inherited { infcx: @mut infer::InferCtxt, locals: @mut HashMap, + param_env: ty::ParameterEnvironment, // Temporary tables: node_types: @mut HashMap, @@ -249,22 +247,25 @@ pub struct FnCtxt { // function return type. fn_kind: FnKind, - in_scope_regions: isr_alist, - - inh: @inherited, + inh: @Inherited, ccx: @mut CrateCtxt, } -pub fn blank_inherited(ccx: @mut CrateCtxt) -> @inherited { - @inherited { - infcx: infer::new_infer_ctxt(ccx.tcx), - locals: @mut HashMap::new(), - node_types: @mut HashMap::new(), - node_type_substs: @mut HashMap::new(), - adjustments: @mut HashMap::new(), - method_map: @mut HashMap::new(), - vtable_map: @mut HashMap::new(), +impl Inherited { + fn new(tcx: ty::ctxt, + param_env: ty::ParameterEnvironment) + -> Inherited { + Inherited { + infcx: infer::new_infer_ctxt(tcx), + locals: @mut HashMap::new(), + param_env: param_env, + node_types: @mut HashMap::new(), + node_type_substs: @mut HashMap::new(), + adjustments: @mut HashMap::new(), + method_map: @mut HashMap::new(), + vtable_map: @mut HashMap::new(), + } } } @@ -272,17 +273,19 @@ pub fn blank_inherited(ccx: @mut CrateCtxt) -> @inherited { pub fn blank_fn_ctxt(ccx: @mut CrateCtxt, rty: ty::t, region_bnd: ast::NodeId) - -> @mut FnCtxt { -// It's kind of a kludge to manufacture a fake function context -// and statement context, but we might as well do write the code only once + -> @mut FnCtxt { + // It's kind of a kludge to manufacture a fake function context + // and statement context, but we might as well do write the code only once + let param_env = ty::ParameterEnvironment { free_substs: substs::empty(), + self_param_bound: None, + type_param_bounds: ~[] }; @mut FnCtxt { err_count_on_creation: ccx.tcx.sess.err_count(), ret_ty: rty, ps: PurityState::function(ast::impure_fn, 0), region_lb: region_bnd, - in_scope_regions: @Nil, fn_kind: Vanilla, - inh: blank_inherited(ccx), + inh: @Inherited::new(ccx.tcx, param_env), ccx: ccx } } @@ -315,14 +318,15 @@ pub fn check_bare_fn(ccx: @mut CrateCtxt, decl: &ast::fn_decl, body: &ast::Block, id: ast::NodeId, - self_info: Option) { - let fty = ty::node_id_to_type(ccx.tcx, id); + self_info: Option, + fty: ty::t, + param_env: ty::ParameterEnvironment) { match ty::get(fty).sty { ty::ty_bare_fn(ref fn_ty) => { let fcx = check_fn(ccx, self_info, fn_ty.purity, &fn_ty.sig, decl, id, body, Vanilla, - @Nil, blank_inherited(ccx));; + @Inherited::new(ccx.tcx, param_env)); vtable::resolve_in_block(fcx, body); regionck::regionck_fn(fcx, body); @@ -411,39 +415,35 @@ pub fn check_fn(ccx: @mut CrateCtxt, id: ast::NodeId, body: &ast::Block, fn_kind: FnKind, - inherited_isr: isr_alist, - inherited: @inherited) -> @mut FnCtxt + inherited: @Inherited) -> @mut FnCtxt { /*! - * * Helper used by check_bare_fn and check_expr_fn. Does the * grungy work of checking a function body and returns the * function context used for that purpose, since in the case of a * fn item there is still a bit more to do. * * - ... - * - inherited_isr: regions in scope from the enclosing fn (if any) * - inherited: other fields inherited from the enclosing fn (if any) */ let tcx = ccx.tcx; let err_count_on_creation = tcx.sess.err_count(); - // ______________________________________________________________________ // First, we have to replace any bound regions in the fn and self // types with free ones. The free region references will be bound // the node_id of the body block. - let (isr, opt_self_info, fn_sig) = { + let (opt_self_info, fn_sig) = { let opt_self_ty = opt_self_info.map(|i| i.self_ty); - let (isr, opt_self_ty, fn_sig) = + let (_, opt_self_ty, fn_sig) = replace_bound_regions_in_fn_sig( - tcx, inherited_isr, opt_self_ty, fn_sig, + tcx, opt_self_ty, fn_sig, |br| ty::re_free(ty::FreeRegion {scope_id: body.id, bound_region: br})); let opt_self_info = opt_self_info.map( |si| SelfInfo {self_ty: opt_self_ty.unwrap(), .. si}); - (isr, opt_self_info, fn_sig) + (opt_self_info, fn_sig) }; relate_free_regions(tcx, opt_self_info.map(|s| s.self_ty), &fn_sig); @@ -456,7 +456,6 @@ pub fn check_fn(ccx: @mut CrateCtxt, ppaux::ty_to_str(tcx, ret_ty), opt_self_info.map(|si| ppaux::ty_to_str(tcx, si.self_ty))); - // ______________________________________________________________________ // Create the function context. This is either derived from scratch or, // in the case of function expressions, based on the outer context. let fcx: @mut FnCtxt = { @@ -465,7 +464,6 @@ pub fn check_fn(ccx: @mut CrateCtxt, ret_ty: ret_ty, ps: PurityState::function(purity, id), region_lb: body.id, - in_scope_regions: isr, fn_kind: fn_kind, inh: inherited, ccx: ccx @@ -536,26 +534,6 @@ pub fn check_fn(ccx: @mut CrateCtxt, } } -pub fn check_method(ccx: @mut CrateCtxt, - method: @ast::method) -{ - let method_def_id = local_def(method.id); - let method_ty = ty::method(ccx.tcx, method_def_id); - let opt_self_info = method_ty.transformed_self_ty.map(|ty| { - SelfInfo {self_ty: ty, - self_id: method.self_id, - span: method.explicit_self.span} - }); - - check_bare_fn( - ccx, - &method.decl, - &method.body, - method.id, - opt_self_info - ); -} - pub fn check_no_duplicate_fields(tcx: ty::ctxt, fields: ~[(ast::Ident, Span)]) { let mut field_names = HashMap::new(); @@ -566,7 +544,7 @@ pub fn check_no_duplicate_fields(tcx: ty::ctxt, match orig_sp { Some(orig_sp) => { tcx.sess.span_err(sp, format!("Duplicate field name {} in record type declaration", - tcx.sess.str_of(id))); + tcx.sess.str_of(id))); tcx.sess.span_note(orig_sp, "First declaration of this field occurred here"); break; } @@ -603,18 +581,32 @@ pub fn check_item(ccx: @mut CrateCtxt, it: @ast::item) { it.id); } ast::item_fn(ref decl, _, _, _, ref body) => { - check_bare_fn(ccx, decl, body, it.id, None); + let fn_tpt = ty::lookup_item_type(ccx.tcx, ast_util::local_def(it.id)); + + // FIXME -- this won't fly for the case where people reference + // a lifetime from within a type parameter. That's actually fairly + // tricky. + let param_env = ty::construct_parameter_environment( + ccx.tcx, + None, + *fn_tpt.generics.type_param_defs, + [], + [], + body.id); + + check_bare_fn(ccx, decl, body, it.id, None, fn_tpt.ty, param_env); } - ast::item_impl(_, _, _, ref ms) => { - let rp = ccx.tcx.region_paramd_items.find(&it.id).map(|x| *x); - debug!("item_impl {} with id {} rp {:?}", - ccx.tcx.sess.str_of(it.ident), it.id, rp); + ast::item_impl(_, ref opt_trait_ref, _, ref ms) => { + debug!("item_impl {} with id {}", ccx.tcx.sess.str_of(it.ident), it.id); + + let impl_tpt = ty::lookup_item_type(ccx.tcx, ast_util::local_def(it.id)); for m in ms.iter() { - check_method(ccx, *m); + check_method_body(ccx, &impl_tpt.generics, None, *m); } vtable::resolve_impl(ccx, it); } ast::item_trait(_, _, ref trait_methods) => { + let trait_def = ty::lookup_trait_def(ccx.tcx, local_def(it.id)); for trait_method in (*trait_methods).iter() { match *trait_method { required(*) => { @@ -622,7 +614,8 @@ pub fn check_item(ccx: @mut CrateCtxt, it: @ast::item) { // bodies to check. } provided(m) => { - check_method(ccx, m); + check_method_body(ccx, &trait_def.generics, + Some(trait_def.trait_ref), m); } } } @@ -662,6 +655,58 @@ pub fn check_item(ccx: @mut CrateCtxt, it: @ast::item) { } } +fn check_method_body(ccx: @mut CrateCtxt, + item_generics: &ty::Generics, + self_bound: Option<@ty::TraitRef>, + method: @ast::method) { + /*! + * Type checks a method body. + * + * # Parameters + * - `item_generics`: generics defined on the impl/trait that contains + * the method + * - `self_bound`: bound for the `Self` type parameter, if any + * - `method`: the method definition + */ + + debug!("check_method_body(item_generics={}, \ + self_bound={}, \ + method.id={})", + item_generics.repr(ccx.tcx), + self_bound.repr(ccx.tcx), + method.id); + let method_def_id = local_def(method.id); + let method_ty = ty::method(ccx.tcx, method_def_id); + let method_generics = &method_ty.generics; + + let param_env = + ty::construct_parameter_environment( + ccx.tcx, + self_bound, + *item_generics.type_param_defs, + *method_generics.type_param_defs, + item_generics.region_param_defs, + method.body.id); + + // Compute the self type and fty from point of view of inside fn + let opt_self_info = method_ty.transformed_self_ty.map(|ty| { + SelfInfo {self_ty: ty.subst(ccx.tcx, ¶m_env.free_substs), + self_id: method.self_id, + span: method.explicit_self.span} + }); + let fty = ty::node_id_to_type(ccx.tcx, method.id); + let fty = fty.subst(ccx.tcx, ¶m_env.free_substs); + + check_bare_fn( + ccx, + &method.decl, + &method.body, + method.id, + opt_self_info, + fty, + param_env); +} + impl AstConv for FnCtxt { fn tcx(&self) -> ty::ctxt { self.ccx.tcx } @@ -682,48 +727,26 @@ impl FnCtxt { pub fn infcx(&self) -> @mut infer::InferCtxt { self.inh.infcx } + pub fn err_count_since_creation(&self) -> uint { self.ccx.tcx.sess.err_count() - self.err_count_on_creation } - pub fn search_in_scope_regions(&self, - span: Span, - br: ty::bound_region) - -> Result { - let in_scope_regions = self.in_scope_regions; - match in_scope_regions.find(br) { - Some(r) => result::Ok(r), - None => { - let blk_br = ty::br_named(special_idents::blk); - if br == blk_br { - result::Ok(self.block_region()) - } else { - result::Err(RegionError { - msg: { - format!("named region `{}` not in scope here", - bound_region_ptr_to_str(self.tcx(), br)) - }, - replacement: { - self.infcx().next_region_var( - infer::BoundRegionError(span)) - } - }) - } - } + + pub fn vtable_context<'a>(&'a self) -> VtableContext<'a> { + VtableContext { + infcx: self.infcx(), + param_env: &self.inh.param_env } } } -impl RegionScope for FnCtxt { - fn anon_region(&self, span: Span) -> Result { - result::Ok(self.infcx().next_region_var(infer::MiscVariable(span))) - } - fn self_region(&self, span: Span) -> Result { - self.search_in_scope_regions(span, ty::br_self) - } - fn named_region(&self, +impl RegionScope for @mut infer::InferCtxt { + fn anon_regions(&self, span: Span, - id: ast::Ident) -> Result { - self.search_in_scope_regions(span, ty::br_named(id)) + count: uint) -> Option<~[ty::Region]> { + Some(vec::from_fn( + count, + |_| self.next_region_var(infer::MiscVariable(span)))) } } @@ -805,7 +828,7 @@ impl FnCtxt { } pub fn to_ty(&self, ast_t: &ast::Ty) -> ty::t { - ast_ty_to_ty(self, self, ast_t) + ast_ty_to_ty(self, &self.infcx(), ast_t) } pub fn pat_to_str(&self, pat: @ast::Pat) -> ~str { @@ -817,7 +840,7 @@ impl FnCtxt { Some(&t) => t, None => { self.tcx().sess.bug(format!("no type for expr in fcx {}", - self.tag())); + self.tag())); } } } @@ -828,10 +851,10 @@ impl FnCtxt { None => { self.tcx().sess.bug( format!("no type for node {}: {} in fcx {}", - id, ast_map::node_id_to_str( - self.tcx().items, id, - token::get_ident_interner()), - self.tag())); + id, ast_map::node_id_to_str( + self.tcx().items, id, + token::get_ident_interner()), + self.tag())); } } } @@ -842,10 +865,9 @@ impl FnCtxt { None => { self.tcx().sess.bug( format!("no type substs for node {}: {} in fcx {}", - id, ast_map::node_id_to_str( - self.tcx().items, id, - token::get_ident_interner()), - self.tag())); + id, ast_map::node_id_to_str(self.tcx().items, id, + token::get_ident_interner()), + self.tag())); } } } @@ -924,20 +946,6 @@ impl FnCtxt { v } - pub fn region_var_if_parameterized(&self, - rp: Option, - span: Span) - -> OptVec { - match rp { - None => opt_vec::Empty, - Some(_) => { - opt_vec::with( - self.infcx().next_region_var( - infer::BoundRegionInTypeOrImpl(span))) - } - } - } - pub fn type_error_message(&self, sp: Span, mk_msg: &fn(~str) -> ~str, @@ -1105,20 +1113,22 @@ pub fn impl_self_ty(vcx: &VtableContext, -> ty_param_substs_and_ty { let tcx = vcx.tcx(); - let (n_tps, region_param, raw_ty) = { + let (n_tps, n_rps, raw_ty) = { let ity = ty::lookup_item_type(tcx, did); - (ity.generics.type_param_defs.len(), ity.generics.region_param, ity.ty) + (ity.generics.type_param_defs.len(), + ity.generics.region_param_defs.len(), + ity.ty) }; - let regions = ty::NonerasedRegions(if region_param.is_some() { - opt_vec::with(vcx.infcx.next_region_var( - infer::BoundRegionInTypeOrImpl(location_info.span))) - } else { - opt_vec::Empty - }); + let rps = + vcx.infcx.next_region_vars( + infer::BoundRegionInTypeOrImpl(location_info.span), + n_rps); let tps = vcx.infcx.next_ty_vars(n_tps); - let substs = substs {regions: regions, self_ty: None, tps: tps}; + let substs = substs {regions: ty::NonerasedRegions(opt_vec::from(rps)), + self_ty: None, + tps: tps}; let substd_ty = ty::subst(tcx, &substs, raw_ty); ty_param_substs_and_ty { substs: substs, ty: substd_ty } @@ -1174,22 +1184,21 @@ fn check_type_parameter_positions_in_path(function_context: @mut FnCtxt, // Verify that no lifetimes or type parameters are present anywhere // except the final two elements of the path. for i in range(0, path.segments.len() - 2) { - match path.segments[i].lifetime { - None => {} - Some(lifetime) => { - function_context.tcx() - .sess - .span_err(lifetime.span, - "lifetime parameters may not \ - appear here") - } + for lifetime in path.segments[i].lifetimes.iter() { + function_context.tcx() + .sess + .span_err(lifetime.span, + "lifetime parameters may not \ + appear here"); + break; } for typ in path.segments[i].types.iter() { function_context.tcx() .sess .span_err(typ.span, - "type parameters may not appear here") + "type parameters may not appear here"); + break; } } @@ -1197,7 +1206,7 @@ fn check_type_parameter_positions_in_path(function_context: @mut FnCtxt, // rest of typechecking will (attempt to) infer everything. if path.segments .iter() - .all(|s| s.lifetime.is_none() && s.types.is_empty()) { + .all(|s| s.lifetimes.is_empty() && s.types.is_empty()) { return } @@ -1219,26 +1228,17 @@ fn check_type_parameter_positions_in_path(function_context: @mut FnCtxt, // Make sure lifetime parameterization agrees with the trait or // implementation type. - match (generics.region_param, trait_segment.lifetime) { - (Some(_), None) => { - function_context.tcx() - .sess - .span_err(path.span, - format!("this {} has a lifetime \ - parameter but no \ - lifetime was specified", - name)) - } - (None, Some(_)) => { - function_context.tcx() - .sess - .span_err(path.span, - format!("this {} has no lifetime \ - parameter but a lifetime \ - was specified", - name)) - } - (Some(_), Some(_)) | (None, None) => {} + let trait_region_parameter_count = generics.region_param_defs.len(); + let supplied_region_parameter_count = trait_segment.lifetimes.len(); + if trait_region_parameter_count != supplied_region_parameter_count + && supplied_region_parameter_count != 0 { + function_context.tcx() + .sess + .span_err(path.span, + format!("expected {} lifetime parameter(s), \ + found {} lifetime parameter(s)", + trait_region_parameter_count, + supplied_region_parameter_count)); } // Make sure the number of type parameters supplied on the trait @@ -1276,15 +1276,13 @@ fn check_type_parameter_positions_in_path(function_context: @mut FnCtxt, // Verify that no lifetimes or type parameters are present on // the penultimate segment of the path. let segment = &path.segments[path.segments.len() - 2]; - match segment.lifetime { - None => {} - Some(lifetime) => { - function_context.tcx() - .sess - .span_err(lifetime.span, - "lifetime parameters may not - appear here") - } + for lifetime in segment.lifetimes.iter() { + function_context.tcx() + .sess + .span_err(lifetime.span, + "lifetime parameters may not + appear here"); + break; } for typ in segment.types.iter() { function_context.tcx() @@ -1292,10 +1290,7 @@ fn check_type_parameter_positions_in_path(function_context: @mut FnCtxt, .span_err(typ.span, "type parameters may not appear \ here"); - function_context.tcx() - .sess - .span_note(typ.span, - format!("this is a {:?}", def)); + break; } } } @@ -1556,7 +1551,7 @@ pub fn check_expr_with_unifier(fcx: @mut FnCtxt, // In that case, we check each argument against "error" in order to // set up all the node type bindings. let error_fn_sig = FnSig { - bound_lifetime_names: opt_vec::Empty, + binder_id: ast::CRATE_NODE_ID, inputs: err_args(args.len()), output: ty::mk_err(), variadic: false @@ -1577,7 +1572,6 @@ pub fn check_expr_with_unifier(fcx: @mut FnCtxt, // signature with region variables let (_, _, fn_sig) = replace_bound_regions_in_fn_sig(fcx.tcx(), - @Nil, None, fn_sig, |br| fcx.infcx() @@ -1908,10 +1902,10 @@ pub fn check_expr_with_unifier(fcx: @mut FnCtxt, expected: Option) { let tcx = fcx.ccx.tcx; - // Find the expected input/output types (if any). Careful to - // avoid capture of bound regions in the expected type. See - // def'n of br_cap_avoid() for a more lengthy explanation of - // what's going on here. + // Find the expected input/output types (if any). Substitute + // fresh bound regions for any bound regions we find in the + // expected types so as to avoid capture. + // // Also try to pick up inferred purity and sigil, defaulting // to impure and block. Note that we only will use those for // block syntax lambdas; that is, lambdas without explicit @@ -1927,11 +1921,10 @@ pub fn check_expr_with_unifier(fcx: @mut FnCtxt, expected_bounds) = { match expected_sty { Some(ty::ty_closure(ref cenv)) => { - let id = expr.id; let (_, _, sig) = replace_bound_regions_in_fn_sig( - tcx, @Nil, None, &cenv.sig, - |br| ty::re_bound(ty::br_cap_avoid(id, @br))); + tcx, None, &cenv.sig, + |_| fcx.inh.infcx.fresh_bound_region(expr.id)); (Some(sig), cenv.purity, cenv.sigil, cenv.onceness, cenv.bounds) } @@ -1952,7 +1945,8 @@ pub fn check_expr_with_unifier(fcx: @mut FnCtxt, // construct the function type let fn_ty = astconv::ty_of_closure(fcx, - fcx, + &fcx.infcx(), + expr.id, sigil, purity, expected_onceness, @@ -1960,13 +1954,12 @@ pub fn check_expr_with_unifier(fcx: @mut FnCtxt, &None, decl, expected_sig, - &opt_vec::Empty, expr.span); let fty_sig; let fty = if error_happened { fty_sig = FnSig { - bound_lifetime_names: opt_vec::Empty, + binder_id: ast::CRATE_NODE_ID, inputs: fn_ty.sig.inputs.map(|_| ty::mk_err()), output: ty::mk_err(), variadic: false @@ -1989,7 +1982,7 @@ pub fn check_expr_with_unifier(fcx: @mut FnCtxt, sigil); check_fn(fcx.ccx, None, inherited_purity, &fty_sig, - decl, id, body, fn_kind, fcx.in_scope_regions, fcx.inh); + decl, id, body, fn_kind, fcx.inh); } @@ -2168,50 +2161,18 @@ pub fn check_expr_with_unifier(fcx: @mut FnCtxt, // Look up the number of type parameters and the raw type, and // determine whether the class is region-parameterized. - let type_parameter_count; - let region_parameterized; - let raw_type; - if class_id.crate == ast::LOCAL_CRATE { - region_parameterized = - tcx.region_paramd_items.find(&class_id.node). - map(|x| *x); - match tcx.items.find(&class_id.node) { - Some(&ast_map::node_item(@ast::item { - node: ast::item_struct(_, ref generics), - _ - }, _)) => { - - type_parameter_count = generics.ty_params.len(); - - let self_region = - bound_self_region(region_parameterized); - - raw_type = ty::mk_struct(tcx, class_id, substs { - regions: ty::NonerasedRegions(self_region), - self_ty: None, - tps: ty::ty_params_to_tys( - tcx, - generics) - }); - } - _ => { - tcx.sess.span_bug(span, - "resolve didn't map this to a class"); - } - } - } else { - let item_type = ty::lookup_item_type(tcx, class_id); - type_parameter_count = item_type.generics.type_param_defs.len(); - region_parameterized = item_type.generics.region_param; - raw_type = item_type.ty; - } + let item_type = ty::lookup_item_type(tcx, class_id); + let type_parameter_count = item_type.generics.type_param_defs.len(); + let region_parameter_count = item_type.generics.region_param_defs.len(); + let raw_type = item_type.ty; // Generate the struct type. - let regions = - fcx.region_var_if_parameterized(region_parameterized, span); + let regions = fcx.infcx().next_region_vars( + infer::BoundRegionInTypeOrImpl(span), + region_parameter_count); let type_parameters = fcx.infcx().next_ty_vars(type_parameter_count); let substitutions = substs { - regions: ty::NonerasedRegions(regions), + regions: ty::NonerasedRegions(opt_vec::from(regions)), self_ty: None, tps: type_parameters }; @@ -2258,48 +2219,18 @@ pub fn check_expr_with_unifier(fcx: @mut FnCtxt, // Look up the number of type parameters and the raw type, and // determine whether the enum is region-parameterized. - let type_parameter_count; - let region_parameterized; - let raw_type; - if enum_id.crate == ast::LOCAL_CRATE { - region_parameterized = - tcx.region_paramd_items.find(&enum_id.node).map(|x| *x); - match tcx.items.find(&enum_id.node) { - Some(&ast_map::node_item(@ast::item { - node: ast::item_enum(_, ref generics), - _ - }, _)) => { - - type_parameter_count = generics.ty_params.len(); - - let regions = bound_self_region(region_parameterized); - - raw_type = ty::mk_enum(tcx, enum_id, substs { - regions: ty::NonerasedRegions(regions), - self_ty: None, - tps: ty::ty_params_to_tys( - tcx, - generics) - }); - } - _ => { - tcx.sess.span_bug(span, - "resolve didn't map this to an enum"); - } - } - } else { - let item_type = ty::lookup_item_type(tcx, enum_id); - type_parameter_count = item_type.generics.type_param_defs.len(); - region_parameterized = item_type.generics.region_param; - raw_type = item_type.ty; - } + let item_type = ty::lookup_item_type(tcx, enum_id); + let type_parameter_count = item_type.generics.type_param_defs.len(); + let region_parameter_count = item_type.generics.region_param_defs.len(); + let raw_type = item_type.ty; // Generate the enum type. - let regions = - fcx.region_var_if_parameterized(region_parameterized, span); + let regions = fcx.infcx().next_region_vars( + infer::BoundRegionInTypeOrImpl(span), + region_parameter_count); let type_parameters = fcx.infcx().next_ty_vars(type_parameter_count); let substitutions = substs { - regions: ty::NonerasedRegions(regions), + regions: ty::NonerasedRegions(opt_vec::from(regions)), self_ty: None, tps: type_parameters }; @@ -3445,28 +3376,25 @@ pub fn instantiate_path(fcx: @mut FnCtxt, ty_param_count, ty_substs_len); - // determine the region bound, using the value given by the user + // determine the region parameters, using the value given by the user // (if any) and otherwise using a fresh region variable - let regions = match pth.segments.last().lifetime { - Some(_) => { // user supplied a lifetime parameter... - match tpt.generics.region_param { - None => { // ...but the type is not lifetime parameterized! - fcx.ccx.tcx.sess.span_err - (span, "this item is not region-parameterized"); - opt_vec::Empty - } - Some(_) => { // ...and the type is lifetime parameterized, ok. - opt_vec::with( - ast_region_to_region(fcx, - fcx, - span, - &pth.segments.last().lifetime)) - } - } - } - None => { // no lifetime parameter supplied, insert default - fcx.region_var_if_parameterized(tpt.generics.region_param, span) + let num_expected_regions = tpt.generics.region_param_defs.len(); + let num_supplied_regions = pth.segments.last().lifetimes.len(); + let regions = if num_expected_regions == num_supplied_regions { + pth.segments.last().lifetimes.map( + |l| ast_region_to_region(fcx.tcx(), l)) + } else { + if num_supplied_regions != 0 { + fcx.ccx.tcx.sess.span_err( + span, + format!("expected {} lifetime parameter(s), \ + found {} lifetime parameter(s)", + num_expected_regions, num_supplied_regions)); } + + opt_vec::from(fcx.infcx().next_region_vars( + infer::BoundRegionInTypeOrImpl(span), + num_expected_regions)) }; // Special case: If there is a self parameter, omit it from the list of @@ -3642,18 +3570,14 @@ pub fn check_bounds_are_used(ccx: @mut CrateCtxt, if tps.len() == 0u { return; } let mut tps_used = vec::from_elem(tps.len(), false); - ty::walk_regions_and_ty( - ccx.tcx, ty, - |_r| {}, - |t| { + ty::walk_ty(ty, |t| { match ty::get(t).sty { - ty::ty_param(param_ty {idx, _}) => { - debug!("Found use of ty param \\#{}", idx); - tps_used[idx] = true; - } - _ => () + ty::ty_param(param_ty {idx, _}) => { + debug!("Found use of ty param \\#{}", idx); + tps_used[idx] = true; + } + _ => () } - true }); for (i, b) in tps_used.iter().enumerate() { @@ -3680,19 +3604,19 @@ pub fn check_intrinsic_type(ccx: @mut CrateCtxt, it: @ast::foreign_item) { //We only care about the operation here match split[1] { "cxchg" => (0, ~[ty::mk_mut_rptr(tcx, - ty::re_bound(ty::br_anon(0)), + ty::re_fn_bound(it.id, ty::br_anon(0)), ty::mk_int()), ty::mk_int(), ty::mk_int() ], ty::mk_int()), "load" => (0, ~[ - ty::mk_imm_rptr(tcx, ty::re_bound(ty::br_anon(0)), ty::mk_int()) + ty::mk_imm_rptr(tcx, ty::re_fn_bound(it.id, ty::br_anon(0)), ty::mk_int()) ], ty::mk_int()), "store" => (0, ~[ - ty::mk_mut_rptr(tcx, ty::re_bound(ty::br_anon(0)), ty::mk_int()), + ty::mk_mut_rptr(tcx, ty::re_fn_bound(it.id, ty::br_anon(0)), ty::mk_int()), ty::mk_int() ], ty::mk_nil()), @@ -3700,7 +3624,7 @@ pub fn check_intrinsic_type(ccx: @mut CrateCtxt, it: @ast::foreign_item) { "xchg" | "xadd" | "xsub" | "and" | "nand" | "or" | "xor" | "max" | "min" | "umax" | "umin" => { (0, ~[ty::mk_mut_rptr(tcx, - ty::re_bound(ty::br_anon(0)), + ty::re_fn_bound(it.id, ty::br_anon(0)), ty::mk_int()), ty::mk_int() ], ty::mk_int()) } "fence" => { @@ -3726,7 +3650,7 @@ pub fn check_intrinsic_type(ccx: @mut CrateCtxt, it: @ast::foreign_item) { "move_val" | "move_val_init" => { (1u, ~[ - ty::mk_mut_rptr(tcx, ty::re_bound(ty::br_anon(0)), param(ccx, 0)), + ty::mk_mut_rptr(tcx, ty::re_fn_bound(it.id, ty::br_anon(0)), param(ccx, 0)), param(ccx, 0u) ], ty::mk_nil()) @@ -3738,7 +3662,7 @@ pub fn check_intrinsic_type(ccx: @mut CrateCtxt, it: @ast::foreign_item) { "atomic_xchg_rel" | "atomic_xadd_rel" | "atomic_xsub_rel" => { (0, ~[ - ty::mk_mut_rptr(tcx, ty::re_bound(ty::br_anon(0)), ty::mk_int()), + ty::mk_mut_rptr(tcx, ty::re_fn_bound(it.id, ty::br_anon(0)), ty::mk_int()), ty::mk_int() ], ty::mk_int()) @@ -3761,7 +3685,7 @@ pub fn check_intrinsic_type(ccx: @mut CrateCtxt, it: @ast::foreign_item) { Ok(t) => t, Err(s) => { tcx.sess.span_fatal(it.span, s); } }; - let region = ty::re_bound(ty::br_anon(0)); + let region = ty::re_fn_bound(it.id, ty::br_anon(0)); let visitor_object_ty = match ty::visitor_object_ty(tcx, region) { Ok((_, vot)) => vot, Err(s) => { tcx.sess.span_fatal(it.span, s); } @@ -3953,12 +3877,10 @@ pub fn check_intrinsic_type(ccx: @mut CrateCtxt, it: @ast::foreign_item) { let fty = ty::mk_bare_fn(tcx, ty::BareFnTy { purity: ast::unsafe_fn, abis: AbiSet::Intrinsic(), - sig: FnSig { - bound_lifetime_names: opt_vec::Empty, - inputs: inputs, - output: output, - variadic: false - } + sig: FnSig {binder_id: it.id, + inputs: inputs, + output: output, + variadic: false} }); let i_ty = ty::lookup_item_type(ccx.tcx, local_def(it.id)); let i_n_tps = i_ty.generics.type_param_defs.len(); @@ -3974,3 +3896,4 @@ pub fn check_intrinsic_type(ccx: @mut CrateCtxt, it: @ast::foreign_item) { ppaux::ty_to_str(ccx.tcx, fty))); } } + diff --git a/src/librustc/middle/typeck/check/regionck.rs b/src/librustc/middle/typeck/check/regionck.rs index c0aa669d920ab..cd94e040ac371 100644 --- a/src/librustc/middle/typeck/check/regionck.rs +++ b/src/librustc/middle/typeck/check/regionck.rs @@ -535,8 +535,14 @@ fn constrain_call(rcx: &mut Rcx, //! appear in the arguments appropriately. let tcx = rcx.fcx.tcx(); - debug!("constrain_call(call_expr={}, implicitly_ref_args={:?})", - call_expr.repr(tcx), implicitly_ref_args); + debug!("constrain_call(call_expr={}, \ + receiver={}, \ + arg_exprs={}, \ + implicitly_ref_args={:?})", + call_expr.repr(tcx), + receiver.repr(tcx), + arg_exprs.repr(tcx), + implicitly_ref_args); let callee_ty = rcx.resolve_node_type(callee_id); if ty::type_is_error(callee_ty) { // Bail, as function type is unknown @@ -552,6 +558,8 @@ fn constrain_call(rcx: &mut Rcx, let callee_region = ty::re_scope(callee_scope); for &arg_expr in arg_exprs.iter() { + debug!("Argument"); + // ensure that any regions appearing in the argument type are // valid for at least the lifetime of the function: constrain_regions_in_type_of_node( @@ -569,6 +577,7 @@ fn constrain_call(rcx: &mut Rcx, // as loop above, but for receiver for &r in receiver.iter() { + debug!("Receiver"); constrain_regions_in_type_of_node( rcx, r.id, callee_region, infer::CallRcvr(r.span)); if implicitly_ref_args { @@ -727,9 +736,9 @@ fn constrain_regions_in_type( ty_to_str(tcx, ty)); do relate_nested_regions(tcx, Some(minimum_lifetime), ty) |r_sub, r_sup| { - debug!("relate(r_sub={}, r_sup={})", - region_to_str(tcx, "", false, r_sub), - region_to_str(tcx, "", false, r_sup)); + debug!("relate_nested_regions(r_sub={}, r_sup={})", + r_sub.repr(tcx), + r_sup.repr(tcx)); if r_sup.is_bound() || r_sub.is_bound() { // a bound region is one which appears inside an fn type. diff --git a/src/librustc/middle/typeck/check/regionmanip.rs b/src/librustc/middle/typeck/check/regionmanip.rs index 9ba709f765106..ea7b2faf27342 100644 --- a/src/librustc/middle/typeck/check/regionmanip.rs +++ b/src/librustc/middle/typeck/check/regionmanip.rs @@ -10,155 +10,41 @@ // #[warn(deprecated_mode)]; - use middle::ty; - -use middle::typeck::isr_alist; -use util::common::indenter; -use util::ppaux::region_to_str; +use middle::ty_fold; +use middle::ty_fold::TypeFolder; +use std::hashmap::HashMap; +use util::ppaux::Repr; use util::ppaux; -use extra::list::Cons; - // Helper functions related to manipulating region types. pub fn replace_bound_regions_in_fn_sig( tcx: ty::ctxt, - isr: isr_alist, opt_self_ty: Option, fn_sig: &ty::FnSig, mapf: &fn(ty::bound_region) -> ty::Region) - -> (isr_alist, Option, ty::FnSig) + -> (HashMap, Option, ty::FnSig) { - let mut all_tys = ty::tys_in_fn_sig(fn_sig); - - for &t in opt_self_ty.iter() { all_tys.push(t) } - - debug!("replace_bound_regions_in_fn_sig(self_ty={:?}, fn_sig={}, \ - all_tys={:?})", - opt_self_ty.map(|t| ppaux::ty_to_str(tcx, t)), - ppaux::fn_sig_to_str(tcx, fn_sig), - all_tys.map(|t| ppaux::ty_to_str(tcx, *t))); - let _i = indenter(); - - let isr = do create_bound_region_mapping(tcx, isr, all_tys) |br| { - debug!("br={:?}", br); - mapf(br) - }; - let new_fn_sig = ty::fold_sig(fn_sig, |t| { - replace_bound_regions(tcx, isr, t) - }); - let new_self_ty = opt_self_ty.map(|t| replace_bound_regions(tcx, isr, t)); - - debug!("result of replace_bound_regions_in_fn_sig: \ - new_self_ty={:?}, \ - fn_sig={}", - new_self_ty.map(|t| ppaux::ty_to_str(tcx, t)), - ppaux::fn_sig_to_str(tcx, &new_fn_sig)); - - return (isr, new_self_ty, new_fn_sig); - - // Takes `isr`, a (possibly empty) mapping from in-scope region - // names ("isr"s) to their corresponding regions; `tys`, a list of - // types, and `to_r`, a closure that takes a bound_region and - // returns a region. Returns an updated version of `isr`, - // extended with the in-scope region names from all of the bound - // regions appearing in the types in the `tys` list (if they're - // not in `isr` already), with each of those in-scope region names - // mapped to a region that's the result of applying `to_r` to - // itself. - fn create_bound_region_mapping( - tcx: ty::ctxt, - isr: isr_alist, - tys: ~[ty::t], - to_r: &fn(ty::bound_region) -> ty::Region) -> isr_alist { - - // Takes `isr` (described above), `to_r` (described above), - // and `r`, a region. If `r` is anything other than a bound - // region, or if it's a bound region that already appears in - // `isr`, then we return `isr` unchanged. If `r` is a bound - // region that doesn't already appear in `isr`, we return an - // updated isr_alist that now contains a mapping from `r` to - // the result of calling `to_r` on it. - fn append_isr(isr: isr_alist, - to_r: &fn(ty::bound_region) -> ty::Region, - r: ty::Region) -> isr_alist { - match r { - ty::re_empty | ty::re_free(*) | ty::re_static | ty::re_scope(_) | - ty::re_infer(_) => { - isr - } - ty::re_bound(br) => { - match isr.find(br) { - Some(_) => isr, - None => @Cons((br, to_r(br)), isr) - } - } - } - } - - // For each type `ty` in `tys`... - do tys.iter().fold(isr) |isr, ty| { - let mut isr = isr; - - // Using fold_regions is inefficient, because it - // constructs new types, but it avoids code duplication in - // terms of locating all the regions within the various - // kinds of types. This had already caused me several - // bugs so I decided to switch over. - do ty::fold_regions(tcx, *ty) |r, in_fn| { - if !in_fn { isr = append_isr(isr, |br| to_r(br), r); } - r - }; - - isr - } - } - - // Takes `isr`, a mapping from in-scope region names ("isr"s) to - // their corresponding regions; and `ty`, a type. Returns an - // updated version of `ty`, in which bound regions in `ty` have - // been replaced with the corresponding bindings in `isr`. - fn replace_bound_regions( - tcx: ty::ctxt, - isr: isr_alist, - ty: ty::t) -> ty::t { - - do ty::fold_regions(tcx, ty) |r, in_fn| { - let r1 = match r { - // As long as we are not within a fn() type, `&T` is - // mapped to the free region anon_r. But within a fn - // type, it remains bound. - ty::re_bound(ty::br_anon(_)) if in_fn => r, - - ty::re_bound(br) => { - match isr.find(br) { - // In most cases, all named, bound regions will be - // mapped to some free region. - Some(fr) => fr, - - // But in the case of a fn() type, there may be - // named regions within that remain bound: - None if in_fn => r, - None => { - tcx.sess.bug( - format!("Bound region not found in \ - in_scope_regions list: {}", - region_to_str(tcx, "", false, r))); - } + debug!("replace_bound_regions_in_fn_sig(self_ty={}, fn_sig={})", + opt_self_ty.repr(tcx), + fn_sig.repr(tcx)); + + let mut map = HashMap::new(); + let (fn_sig, opt_self_ty) = { + let mut f = ty_fold::RegionFolder::regions(tcx, |r| { + debug!("region r={}", r.to_str()); + match r { + ty::re_fn_bound(s, br) if s == fn_sig.binder_id => { + *map.find_or_insert_with(br, |_| mapf(br)) } - } - - // Free regions like these just stay the same: - ty::re_empty | - ty::re_static | - ty::re_scope(_) | - ty::re_free(*) | - ty::re_infer(_) => r - }; - r1 - } - } + _ => r + }}); + (ty_fold::super_fold_sig(&mut f, fn_sig), + ty_fold::fold_opt_ty(&mut f, opt_self_ty)) + }; + debug!("resulting map: {}", map.to_str()); + (map, opt_self_ty, fn_sig) } pub fn relate_nested_regions( @@ -168,7 +54,6 @@ pub fn relate_nested_regions( relate_op: &fn(ty::Region, ty::Region)) { /*! - * * This rather specialized function walks each region `r` that appear * in `ty` and invokes `relate_op(r_encl, r)` for each one. `r_encl` * here is the region of any enclosing `&'r T` pointer. If there is @@ -194,41 +79,66 @@ pub fn relate_nested_regions( * Hence, in the second example above, `'r2` must be a subregion of `'r3`. */ - let mut the_stack = ~[]; - for &r in opt_region.iter() { the_stack.push(r); } - walk_ty(tcx, &mut the_stack, ty, relate_op); + let mut rr = RegionRelator { tcx: tcx, + stack: ~[], + relate_op: relate_op }; + match opt_region { + Some(o_r) => { rr.stack.push(o_r); } + None => {} + } + rr.fold_ty(ty); - fn walk_ty(tcx: ty::ctxt, - the_stack: &mut ~[ty::Region], - ty: ty::t, - relate_op: &fn(ty::Region, ty::Region)) - { - match ty::get(ty).sty { - ty::ty_rptr(r, ref mt) | - ty::ty_evec(ref mt, ty::vstore_slice(r)) => { - relate(*the_stack, r, |x,y| relate_op(x,y)); - the_stack.push(r); - walk_ty(tcx, the_stack, mt.ty, |x,y| relate_op(x,y)); - the_stack.pop(); - } - _ => { - ty::fold_regions_and_ty( - tcx, - ty, - |r| { relate( *the_stack, r, |x,y| relate_op(x,y)); r }, - |t| { walk_ty(tcx, the_stack, t, |x,y| relate_op(x,y)); t }, - |t| { walk_ty(tcx, the_stack, t, |x,y| relate_op(x,y)); t }); + struct RegionRelator<'self> { + tcx: ty::ctxt, + stack: ~[ty::Region], + relate_op: &'self fn(ty::Region, ty::Region), + } + + // FIXME we should define more precisely when a + // region is considered "nested" and take variance into account. + // + // I can't decide whether skipping closure parameter types and + // so on is necessary or not. What is the difference, after all, + // between `&'a |&'b T|` and `&'a Fn<&'b T>`? And yet in the + // latter case I'm inclined to think we should probably track + // the relationship (but then again maybe we should just skip + // all such cases until it "proves necessary") + + impl<'self> TypeFolder for RegionRelator<'self> { + fn tcx(&self) -> ty::ctxt { + self.tcx + } + + fn fold_ty(&mut self, ty: ty::t) -> ty::t { + match ty::get(ty).sty { + ty::ty_rptr(r, ref mt) | + ty::ty_evec(ref mt, ty::vstore_slice(r)) => { + self.relate(r); + self.stack.push(r); + ty_fold::super_fold_ty(self, mt.ty); + self.stack.pop(); + } + + _ => { + ty_fold::super_fold_ty(self, ty); + } } + + ty + } + + fn fold_region(&mut self, r: ty::Region) -> ty::Region { + self.relate(r); + r } } - fn relate(the_stack: &[ty::Region], - r_sub: ty::Region, - relate_op: &fn(ty::Region, ty::Region)) - { - for &r in the_stack.iter() { - if !r.is_bound() && !r_sub.is_bound() { - relate_op(r, r_sub); + impl<'self> RegionRelator<'self> { + fn relate(&mut self, r_sub: ty::Region) { + for &r in self.stack.iter() { + if !r.is_bound() && !r_sub.is_bound() { + (self.relate_op)(r, r_sub); + } } } } diff --git a/src/librustc/middle/typeck/check/vtable.rs b/src/librustc/middle/typeck/check/vtable.rs index 3c4ff35b768db..ae76c9ed6dd49 100644 --- a/src/librustc/middle/typeck/check/vtable.rs +++ b/src/librustc/middle/typeck/check/vtable.rs @@ -11,6 +11,7 @@ use middle::ty::param_ty; use middle::ty; +use middle::ty_fold::TypeFolder; use middle::typeck::check::{FnCtxt, impl_self_ty}; use middle::typeck::check::{structurally_resolved_type}; use middle::typeck::infer::fixup_err_to_str; @@ -68,13 +69,13 @@ pub struct LocationInfo { /// A vtable context includes an inference context, a crate context, and a /// callback function to call in case of type error. -pub struct VtableContext { - ccx: @mut CrateCtxt, - infcx: @mut infer::InferCtxt +pub struct VtableContext<'self> { + infcx: @mut infer::InferCtxt, + param_env: &'self ty::ParameterEnvironment, } -impl VtableContext { - pub fn tcx(&self) -> ty::ctxt { self.ccx.tcx } +impl<'self> VtableContext<'self> { + pub fn tcx(&self) -> ty::ctxt { self.infcx.tcx } } fn has_trait_bounds(type_param_defs: &[ty::TypeParameterDef]) -> bool { @@ -95,7 +96,6 @@ fn lookup_vtables(vcx: &VtableContext, substs.repr(vcx.tcx())); let _i = indenter(); - // We do this backwards for reasons discussed above. assert_eq!(substs.tps.len(), type_param_defs.len()); let mut result = @@ -233,8 +233,6 @@ fn lookup_vtable(vcx: &VtableContext, vcx.infcx.trait_ref_to_str(trait_ref)); let _i = indenter(); - let tcx = vcx.tcx(); - let ty = match fixup_ty(vcx, location_info, ty, is_early) { Some(ty) => ty, None => { @@ -250,18 +248,21 @@ fn lookup_vtable(vcx: &VtableContext, // If the type is self or a param, we look at the trait/supertrait // bounds to see if they include the trait we are looking for. let vtable_opt = match ty::get(ty).sty { - ty::ty_param(param_ty {idx: n, def_id: did}) => { - let type_param_def = tcx.ty_param_defs.get(&did.node); - lookup_vtable_from_bounds(vcx, location_info, - type_param_def.bounds.trait_bounds, + ty::ty_param(param_ty {idx: n, _}) => { + let type_param_bounds: &[@ty::TraitRef] = + vcx.param_env.type_param_bounds[n].trait_bounds; + lookup_vtable_from_bounds(vcx, + location_info, + type_param_bounds, param_numbered(n), trait_ref) } - ty::ty_self(trait_id) => { - let self_trait_ref = ty::lookup_trait_def(tcx, trait_id).trait_ref; - lookup_vtable_from_bounds(vcx, location_info, - &[self_trait_ref], + ty::ty_self(_) => { + let self_param_bound = vcx.param_env.self_param_bound.unwrap(); + lookup_vtable_from_bounds(vcx, + location_info, + [self_param_bound], param_self, trait_ref) } @@ -285,7 +286,7 @@ fn lookup_vtable_from_bounds(vcx: &VtableContext, bounds: &[@ty::TraitRef], param: param_index, trait_ref: @ty::TraitRef) - -> Option { + -> Option { let tcx = vcx.tcx(); let mut n_bound = 0; @@ -317,8 +318,7 @@ fn search_for_vtable(vcx: &VtableContext, ty: ty::t, trait_ref: @ty::TraitRef, is_early: bool) - -> Option -{ + -> Option { let tcx = vcx.tcx(); let mut found = ~[]; @@ -494,7 +494,8 @@ fn fixup_substs(vcx: &VtableContext, fn fixup_ty(vcx: &VtableContext, location_info: &LocationInfo, ty: ty::t, - is_early: bool) -> Option { + is_early: bool) + -> Option { let tcx = vcx.tcx(); match resolve_type(vcx.infcx, ty, resolve_and_force_all_but_regions) { Ok(new_type) => Some(new_type), @@ -515,8 +516,7 @@ fn connect_trait_tps(vcx: &VtableContext, location_info: &LocationInfo, impl_substs: &ty::substs, trait_ref: @ty::TraitRef, - impl_did: ast::DefId) -{ + impl_did: ast::DefId) { let tcx = vcx.tcx(); let impl_trait_ref = match ty::impl_trait_ref(tcx, impl_did) { @@ -571,7 +571,7 @@ pub fn early_resolve_expr(ex: @ast::Expr, if has_trait_bounds(*item_ty.generics.type_param_defs) { debug!("early_resolve_expr: looking up vtables for type params {}", item_ty.generics.type_param_defs.repr(fcx.tcx())); - let vcx = VtableContext { ccx: fcx.ccx, infcx: fcx.infcx() }; + let vcx = fcx.vtable_context(); let vtbls = lookup_vtables(&vcx, &location_info_for_expr(ex), *item_ty.generics.type_param_defs, substs, is_early); @@ -599,7 +599,7 @@ pub fn early_resolve_expr(ex: @ast::Expr, ex.repr(fcx.tcx())); if has_trait_bounds(*type_param_defs) { let substs = fcx.node_ty_substs(callee_id); - let vcx = VtableContext { ccx: fcx.ccx, infcx: fcx.infcx() }; + let vcx = fcx.vtable_context(); let vtbls = lookup_vtables(&vcx, &location_info_for_expr(ex), *type_param_defs, &substs, is_early); if !is_early { @@ -642,10 +642,7 @@ pub fn early_resolve_expr(ex: @ast::Expr, (&ty::ty_rptr(_, mt), ty::RegionTraitStore(*)) => { let location_info = &location_info_for_expr(ex); - let vcx = VtableContext { - ccx: fcx.ccx, - infcx: fcx.infcx() - }; + let vcx = fcx.vtable_context(); let target_trait_ref = @ty::TraitRef { def_id: target_def_id, substs: ty::substs { @@ -726,48 +723,58 @@ fn resolve_expr(fcx: @mut FnCtxt, visit::walk_expr(&mut fcx, ex, ()); } -pub fn resolve_impl(ccx: @mut CrateCtxt, impl_item: @ast::item) { - let def_id = ast_util::local_def(impl_item.id); - match ty::impl_trait_ref(ccx.tcx, def_id) { - None => {}, - Some(trait_ref) => { - let infcx = infer::new_infer_ctxt(ccx.tcx); - let vcx = VtableContext { ccx: ccx, infcx: infcx }; - let loc_info = location_info_for_item(impl_item); - - // First, check that the impl implements any trait bounds - // on the trait. - let trait_def = ty::lookup_trait_def(ccx.tcx, trait_ref.def_id); - let vtbls = lookup_vtables(&vcx, - &loc_info, - *trait_def.generics.type_param_defs, - &trait_ref.substs, - false); - - // Now, locate the vtable for the impl itself. The real - // purpose of this is to check for supertrait impls, - // but that falls out of doing this. - let param_bounds = ty::ParamBounds { - builtin_bounds: ty::EmptyBuiltinBounds(), - trait_bounds: ~[trait_ref] - }; - let t = ty::node_id_to_type(ccx.tcx, impl_item.id); - debug!("=== Doing a self lookup now."); - // Right now, we don't have any place to store this. - // We will need to make one so we can use this information - // for compiling default methods that refer to supertraits. - let self_vtable_res = - lookup_vtables_for_param(&vcx, &loc_info, None, - ¶m_bounds, t, false); - - - let res = impl_res { - trait_vtables: vtbls, - self_vtables: self_vtable_res - }; - ccx.tcx.impl_vtables.insert(def_id, res); - } - } +pub fn resolve_impl(ccx: @mut CrateCtxt, + impl_item: @ast::item, + impl_generics: &ty::Generics, + impl_trait_ref: &ty::TraitRef) { + let param_env = ty::construct_parameter_environment( + ccx.tcx, + None, + *impl_generics.type_param_defs, + [], + impl_generics.region_param_defs, + impl_item.id); + + let impl_trait_ref = @impl_trait_ref.subst(ccx.tcx, ¶m_env.free_substs); + + let infcx = infer::new_infer_ctxt(ccx.tcx); + let vcx = VtableContext { infcx: infcx, param_env: ¶m_env }; + let loc_info = location_info_for_item(impl_item); + + // First, check that the impl implements any trait bounds + // on the trait. + let trait_def = ty::lookup_trait_def(ccx.tcx, impl_trait_ref.def_id); + let vtbls = lookup_vtables(&vcx, + &loc_info, + *trait_def.generics.type_param_defs, + &impl_trait_ref.substs, + false); + + // Now, locate the vtable for the impl itself. The real + // purpose of this is to check for supertrait impls, + // but that falls out of doing this. + let param_bounds = ty::ParamBounds { + builtin_bounds: ty::EmptyBuiltinBounds(), + trait_bounds: ~[impl_trait_ref] + }; + let t = ty::node_id_to_type(ccx.tcx, impl_item.id); + let t = t.subst(ccx.tcx, ¶m_env.free_substs); + debug!("=== Doing a self lookup now."); + + // Right now, we don't have any place to store this. + // We will need to make one so we can use this information + // for compiling default methods that refer to supertraits. + let self_vtable_res = + lookup_vtables_for_param(&vcx, &loc_info, None, + ¶m_bounds, t, false); + + + let res = impl_res { + trait_vtables: vtbls, + self_vtables: self_vtable_res + }; + let impl_def_id = ast_util::local_def(impl_item.id); + ccx.tcx.impl_vtables.insert(impl_def_id, res); } impl visit::Visitor<()> for @mut FnCtxt { diff --git a/src/librustc/middle/typeck/coherence.rs b/src/librustc/middle/typeck/coherence.rs index 795074fa61904..b959c80db38a8 100644 --- a/src/librustc/middle/typeck/coherence.rs +++ b/src/librustc/middle/typeck/coherence.rs @@ -357,8 +357,8 @@ impl CoherenceChecker { @vec::append( (*impl_poly_type.generics.type_param_defs).clone(), *new_method_ty.generics.type_param_defs), - region_param: - impl_poly_type.generics.region_param + region_param_defs: + impl_poly_type.generics.region_param_defs }; let new_polytype = ty::ty_param_bounds_and_ty { generics: new_generics, @@ -482,20 +482,17 @@ impl CoherenceChecker { pub fn universally_quantify_polytype(&self, polytype: ty_param_bounds_and_ty) -> UniversalQuantificationResult { - let regions = match polytype.generics.region_param { - None => opt_vec::Empty, - Some(_) => { - opt_vec::with( - self.inference_context.next_region_var( - infer::BoundRegionInCoherence)) - } - }; + let region_parameter_count = polytype.generics.region_param_defs.len(); + let region_parameters = + self.inference_context.next_region_vars( + infer::BoundRegionInCoherence, + region_parameter_count); let bounds_count = polytype.generics.type_param_defs.len(); let type_parameters = self.inference_context.next_ty_vars(bounds_count); let substitutions = substs { - regions: ty::NonerasedRegions(regions), + regions: ty::NonerasedRegions(opt_vec::from(region_parameters)), self_ty: None, tps: type_parameters }; diff --git a/src/librustc/middle/typeck/collect.rs b/src/librustc/middle/typeck/collect.rs index 353639051097a..c1908e69f1e09 100644 --- a/src/librustc/middle/typeck/collect.rs +++ b/src/librustc/middle/typeck/collect.rs @@ -39,15 +39,10 @@ use middle::subst::Subst; use middle::typeck::astconv::{AstConv, ty_of_arg}; use middle::typeck::astconv::{ast_ty_to_ty}; use middle::typeck::astconv; -use middle::typeck::infer; use middle::typeck::rscope::*; -use middle::typeck::rscope; use middle::typeck::{CrateCtxt, lookup_def_tcx, no_params, write_ty_to_tcx}; -use util::common::pluralize; use util::ppaux; -use util::ppaux::UserString; -use std::result; use std::vec; use syntax::abi::AbiSet; use syntax::ast::{RegionTyParamBound, TraitTyParamBound}; @@ -56,10 +51,9 @@ use syntax::ast_map; use syntax::ast_util::{local_def, split_trait_methods}; use syntax::codemap::Span; use syntax::codemap; -use syntax::print::pprust::{path_to_str, explicit_self_to_str}; +use syntax::print::pprust::{path_to_str}; use syntax::visit; use syntax::opt_vec::OptVec; -use syntax::opt_vec; use syntax::parse::token::special_idents; struct CollectItemTypesVisitor { @@ -97,19 +91,11 @@ pub fn collect_item_types(ccx: @mut CrateCtxt, crate: &ast::Crate) { } pub trait ToTy { - fn to_ty( - &self, - rs: &RS, - ast_ty: &ast::Ty) - -> ty::t; + fn to_ty(&self, rs: &RS, ast_ty: &ast::Ty) -> ty::t; } impl ToTy for CrateCtxt { - fn to_ty( - &self, - rs: &RS, - ast_ty: &ast::Ty) - -> ty::t { + fn to_ty(&self, rs: &RS, ast_ty: &ast::Ty) -> ty::t { ast_ty_to_ty(self, rs, ast_ty) } } @@ -149,59 +135,45 @@ impl AstConv for CrateCtxt { pub fn get_enum_variant_types(ccx: &CrateCtxt, enum_ty: ty::t, variants: &[ast::variant], - generics: &ast::Generics, - rp: Option) { + generics: &ast::Generics) { let tcx = ccx.tcx; // Create a set of parameter types shared among all the variants. for variant in variants.iter() { - let region_parameterization = - RegionParameterization::from_variance_and_generics(rp, generics); - // Nullary enum constructors get turned into constants; n-ary enum // constructors get turned into functions. - let result_ty; - match variant.node.kind { + let scope = variant.node.id; + let result_ty = match variant.node.kind { ast::tuple_variant_kind(ref args) if args.len() > 0 => { - let rs = TypeRscope(region_parameterization); + let rs = ExplicitRscope; let input_tys = args.map(|va| ccx.to_ty(&rs, &va.ty)); - result_ty = Some(ty::mk_ctor_fn(tcx, input_tys, enum_ty)); + ty::mk_ctor_fn(tcx, scope, input_tys, enum_ty) } ast::tuple_variant_kind(_) => { - result_ty = Some(enum_ty); + enum_ty } ast::struct_variant_kind(struct_def) => { let tpt = ty_param_bounds_and_ty { - generics: ty_generics(ccx, rp, generics, 0), + generics: ty_generics(ccx, generics, 0), ty: enum_ty }; - convert_struct(ccx, - rp, - struct_def, - generics, - tpt, - variant.node.id); + convert_struct(ccx, struct_def, tpt, variant.node.id); let input_tys = struct_def.fields.map( |f| ty::node_id_to_type(ccx.tcx, f.node.id)); - result_ty = Some(ty::mk_ctor_fn(tcx, input_tys, enum_ty)); + ty::mk_ctor_fn(tcx, scope, input_tys, enum_ty) } }; - match result_ty { - None => {} - Some(result_ty) => { - let tpt = ty_param_bounds_and_ty { - generics: ty_generics(ccx, rp, generics, 0), - ty: result_ty - }; - tcx.tcache.insert(local_def(variant.node.id), tpt); - write_ty_to_tcx(tcx, variant.node.id, result_ty); - } - } + let tpt = ty_param_bounds_and_ty { + generics: ty_generics(ccx, generics, 0), + ty: result_ty + }; + tcx.tcache.insert(local_def(variant.node.id), tpt); + write_ty_to_tcx(tcx, variant.node.id, result_ty); } } @@ -209,13 +181,13 @@ pub fn ensure_trait_methods(ccx: &CrateCtxt, trait_id: ast::NodeId) { let tcx = ccx.tcx; - let region_paramd = tcx.region_paramd_items.find(&trait_id).map(|x| *x); match tcx.items.get_copy(&trait_id) { ast_map::node_item(@ast::item { node: ast::item_trait(ref generics, _, ref ms), _ }, _) => { - let trait_ty_generics = ty_generics(ccx, region_paramd, generics, 0); + let trait_ty_generics = + ty_generics(ccx, generics, 0); // For each method, construct a suitable ty::Method and // store it into the `tcx.methods` table: @@ -223,14 +195,14 @@ pub fn ensure_trait_methods(ccx: &CrateCtxt, let ty_method = @match m { &ast::required(ref m) => { ty_method_of_trait_method( - ccx, trait_id, region_paramd, generics, + ccx, trait_id, &trait_ty_generics, &m.id, &m.ident, &m.explicit_self, &m.generics, &m.purity, &m.decl) } &ast::provided(ref m) => { ty_method_of_trait_method( - ccx, trait_id, region_paramd, generics, + ccx, trait_id, &trait_ty_generics, &m.id, &m.ident, &m.explicit_self, &m.generics, &m.purity, &m.decl) } @@ -264,13 +236,13 @@ pub fn ensure_trait_methods(ccx: &CrateCtxt, trait_ty_generics: &ty::Generics) { // If declaration is // - // trait { - // fn foo(...) -> Self; + // trait<'a,'b,'c,A,B,C> { + // fn foo<'d,'e,'f,D,E,F>(...) -> Self; // } // // and we will create a function like // - // fn foo(...) -> D' {} + // fn foo<'a,'b,'c,'d,'e,'f,A',B',C',D',E',F',G'>(...) -> D' {} // // Note that `Self` is replaced with an explicit type // parameter D' that is sandwiched in between the trait params @@ -307,12 +279,19 @@ pub fn ensure_trait_methods(ccx: &CrateCtxt, m.generics.type_param_defs[i].def_id) }; + // Convert the regions 'a, 'b, 'c defined on the trait into + // bound regions on the fn. + let rps_from_trait = trait_ty_generics.region_param_defs.iter().map(|d| { + ty::re_fn_bound(m.fty.sig.binder_id, + ty::br_named(d.def_id, d.ident)) + }).collect(); + // build up the substitution from // A,B,C => A',B',C' // Self => D' // D,E,F => E',F',G' let substs = substs { - regions: ty::NonerasedRegions(opt_vec::Empty), + regions: ty::NonerasedRegions(rps_from_trait), self_ty: Some(self_param), tps: non_shifted_trait_tps + shifted_method_tps }; @@ -357,7 +336,7 @@ pub fn ensure_trait_methods(ccx: &CrateCtxt, ty_param_bounds_and_ty { generics: ty::Generics { type_param_defs: @new_type_param_defs, - region_param: trait_ty_generics.region_param + region_param_defs: @[], // fn items }, ty: ty }); @@ -365,8 +344,7 @@ pub fn ensure_trait_methods(ccx: &CrateCtxt, fn ty_method_of_trait_method(this: &CrateCtxt, trait_id: ast::NodeId, - trait_rp: Option, - trait_generics: &ast::Generics, + trait_generics: &ty::Generics, m_id: &ast::NodeId, m_ident: &ast::Ident, m_explicit_self: &ast::explicit_self, @@ -375,14 +353,14 @@ pub fn ensure_trait_methods(ccx: &CrateCtxt, m_decl: &ast::fn_decl) -> ty::Method { let trait_self_ty = ty::mk_self(this.tcx, local_def(trait_id)); - let rscope = MethodRscope::new(m_explicit_self.node, trait_rp, trait_generics); let (transformed_self_ty, fty) = - astconv::ty_of_method(this, &rscope, *m_purity, &m_generics.lifetimes, + astconv::ty_of_method(this, *m_id, *m_purity, trait_self_ty, *m_explicit_self, m_decl); - let num_trait_type_params = trait_generics.ty_params.len(); + let num_trait_type_params = trait_generics.type_param_defs.len(); ty::Method::new( *m_ident, - ty_generics(this, None, m_generics, num_trait_type_params), + // FIXME -- what about lifetime parameters here? + ty_generics(this, m_generics, num_trait_type_params), transformed_self_ty, fty, m_explicit_self.node, @@ -398,9 +376,8 @@ pub fn ensure_trait_methods(ccx: &CrateCtxt, pub fn ensure_supertraits(ccx: &CrateCtxt, id: ast::NodeId, sp: codemap::Span, - rp: Option, - ast_trait_refs: &[ast::trait_ref], - generics: &ast::Generics) -> ty::BuiltinBounds + ast_trait_refs: &[ast::trait_ref]) + -> ty::BuiltinBounds { let tcx = ccx.tcx; @@ -416,8 +393,7 @@ pub fn ensure_supertraits(ccx: &CrateCtxt, // FIXME(#8559): Need to instantiate the trait_ref whether or not it's a // builtin trait, so that the trait's node id appears in the tcx trait_ref // map. This is only needed for metadata; see the similar fixme in encoder.rs. - let trait_ref = instantiate_trait_ref(ccx, ast_trait_ref, rp, - generics, self_ty); + let trait_ref = instantiate_trait_ref(ccx, ast_trait_ref, self_ty); if !ty::try_add_builtin_trait(ccx.tcx, trait_def_id, &mut bounds) { // FIXME(#5527) Could have same trait multiple times @@ -720,91 +696,68 @@ pub fn check_methods_against_trait(ccx: &CrateCtxt, } // fn pub fn convert_field(ccx: &CrateCtxt, - rp: Option, - type_param_defs: @~[ty::TypeParameterDef], - v: &ast::struct_field, - generics: &ast::Generics) { - let region_parameterization = - RegionParameterization::from_variance_and_generics(rp, generics); - let tt = ccx.to_ty(&TypeRscope(region_parameterization), &v.node.ty); + struct_generics: &ty::Generics, + v: &ast::struct_field) { + let tt = ccx.to_ty(&ExplicitRscope, &v.node.ty); write_ty_to_tcx(ccx.tcx, v.node.id, tt); /* add the field to the tcache */ ccx.tcx.tcache.insert(local_def(v.node.id), ty::ty_param_bounds_and_ty { - generics: ty::Generics { - type_param_defs: type_param_defs, - region_param: rp - }, + generics: struct_generics.clone(), ty: tt }); } -pub struct ConvertedMethod { - mty: @ty::Method, - id: ast::NodeId, - span: Span, - body_id: ast::NodeId -} - -pub fn convert_methods(ccx: &CrateCtxt, - container: MethodContainer, - ms: &[@ast::method], - untransformed_rcvr_ty: ty::t, - rcvr_ty_generics: &ty::Generics, - rcvr_ast_generics: &ast::Generics, - rcvr_visibility: ast::visibility) - -> ~[ConvertedMethod] +fn convert_methods(ccx: &CrateCtxt, + container: MethodContainer, + ms: &[@ast::method], + untransformed_rcvr_ty: ty::t, + rcvr_ty_generics: &ty::Generics, + rcvr_ast_generics: &ast::Generics, + rcvr_visibility: ast::visibility) { let tcx = ccx.tcx; - return ms.iter().map(|m| { + for m in ms.iter() { let num_rcvr_ty_params = rcvr_ty_generics.type_param_defs.len(); - let m_ty_generics = - ty_generics(ccx, rcvr_ty_generics.region_param, &m.generics, - num_rcvr_ty_params); + let m_ty_generics = ty_generics(ccx, &m.generics, num_rcvr_ty_params); let mty = @ty_of_method(ccx, container, *m, - rcvr_ty_generics.region_param, untransformed_rcvr_ty, rcvr_ast_generics, - rcvr_visibility, - &m.generics); + rcvr_visibility); let fty = ty::mk_bare_fn(tcx, mty.fty.clone()); + debug!("method {} (id {}) has type {}", + m.ident.repr(ccx.tcx), + m.id, + fty.repr(ccx.tcx)); tcx.tcache.insert( local_def(m.id), // n.b.: the type of a method is parameterized by both - // the tps on the receiver and those on the method itself + // the parameters on the receiver and those on the method itself ty_param_bounds_and_ty { generics: ty::Generics { type_param_defs: @vec::append( (*rcvr_ty_generics.type_param_defs).clone(), *m_ty_generics.type_param_defs), - region_param: rcvr_ty_generics.region_param + region_param_defs: rcvr_ty_generics.region_param_defs, }, ty: fty }); write_ty_to_tcx(tcx, m.id, fty); tcx.methods.insert(mty.def_id, mty); - ConvertedMethod {mty: mty, id: m.id, - span: m.span, body_id: m.body.id} - }).collect(); + } fn ty_of_method(ccx: &CrateCtxt, container: MethodContainer, m: &ast::method, - rp: Option, untransformed_rcvr_ty: ty::t, rcvr_generics: &ast::Generics, - rcvr_visibility: ast::visibility, - method_generics: &ast::Generics) -> ty::Method + rcvr_visibility: ast::visibility) -> ty::Method { - let rscope = MethodRscope::new(m.explicit_self.node, - rp, - rcvr_generics); let (transformed_self_ty, fty) = - astconv::ty_of_method(ccx, &rscope, m.purity, - &method_generics.lifetimes, + astconv::ty_of_method(ccx, m.id, m.purity, untransformed_rcvr_ty, m.explicit_self, &m.decl); @@ -817,7 +770,8 @@ pub fn convert_methods(ccx: &CrateCtxt, let num_rcvr_type_params = rcvr_generics.ty_params.len(); ty::Method::new( m.ident, - ty_generics(ccx, None, &m.generics, num_rcvr_type_params), + // FIXME region param + ty_generics(ccx, &m.generics, num_rcvr_type_params), transformed_self_ty, fty, m.explicit_self.node, @@ -845,27 +799,22 @@ pub fn ensure_no_ty_param_bounds(ccx: &CrateCtxt, pub fn convert(ccx: &CrateCtxt, it: &ast::item) { let tcx = ccx.tcx; - let rp = tcx.region_paramd_items.find(&it.id).map(|x| *x); - debug!("convert: item {} with id {} rp {:?}", - tcx.sess.str_of(it.ident), it.id, rp); + debug!("convert: item {} with id {}", tcx.sess.str_of(it.ident), it.id); match it.node { - // These don't define types. - ast::item_foreign_mod(_) | ast::item_mod(_) => {} - ast::item_enum(ref enum_definition, ref generics) => { - ensure_no_ty_param_bounds(ccx, it.span, generics, "enumeration"); - let tpt = ty_of_item(ccx, it); - write_ty_to_tcx(tcx, it.id, tpt.ty); - get_enum_variant_types(ccx, - tpt.ty, - enum_definition.variants, - generics, - rp); - } + // These don't define types. + ast::item_foreign_mod(_) | ast::item_mod(_) => {} + ast::item_enum(ref enum_definition, ref generics) => { + ensure_no_ty_param_bounds(ccx, it.span, generics, "enumeration"); + let tpt = ty_of_item(ccx, it); + write_ty_to_tcx(tcx, it.id, tpt.ty); + get_enum_variant_types(ccx, + tpt.ty, + enum_definition.variants, + generics); + } ast::item_impl(ref generics, ref opt_trait_ref, ref selfty, ref ms) => { - let i_ty_generics = ty_generics(ccx, rp, generics, 0); - let region_parameterization = - RegionParameterization::from_variance_and_generics(rp, generics); - let selfty = ccx.to_ty(&TypeRscope(region_parameterization), selfty); + let i_ty_generics = ty_generics(ccx, generics, 0); + let selfty = ccx.to_ty(&ExplicitRscope, selfty); write_ty_to_tcx(tcx, it.id, selfty); tcx.tcache.insert(local_def(it.id), ty_param_bounds_and_ty { @@ -883,17 +832,19 @@ pub fn convert(ccx: &CrateCtxt, it: &ast::item) { it.vis }; - let cms = convert_methods(ccx, - ImplContainer(local_def(it.id)), - *ms, - selfty, - &i_ty_generics, - generics, - parent_visibility); - for t in opt_trait_ref.iter() { + convert_methods(ccx, + ImplContainer(local_def(it.id)), + *ms, + selfty, + &i_ty_generics, + generics, + parent_visibility); + + for trait_ref in opt_trait_ref.iter() { + let trait_ref = instantiate_trait_ref(ccx, trait_ref, selfty); + // Prevent the builtin kind traits from being manually implemented. - let trait_def_id = ty::trait_ref_to_def_id(tcx, t); - if tcx.lang_items.to_builtin_kind(trait_def_id).is_some() { + if tcx.lang_items.to_builtin_kind(trait_ref.def_id).is_some() { tcx.sess.span_err(it.span, "cannot provide an explicit implementation \ for a builtin kind"); @@ -903,21 +854,19 @@ pub fn convert(ccx: &CrateCtxt, it: &ast::item) { } } ast::item_trait(ref generics, _, ref trait_methods) => { - let _trait_def = trait_def_of_item(ccx, it); + let trait_def = trait_def_of_item(ccx, it); // Run convert_methods on the provided methods. let (_, provided_methods) = split_trait_methods(*trait_methods); let untransformed_rcvr_ty = ty::mk_self(tcx, local_def(it.id)); - let (ty_generics, _) = mk_item_substs(ccx, generics, rp, - Some(untransformed_rcvr_ty)); - let _ = convert_methods(ccx, - TraitContainer(local_def(it.id)), - provided_methods, - untransformed_rcvr_ty, - &ty_generics, - generics, - it.vis); + convert_methods(ccx, + TraitContainer(local_def(it.id)), + provided_methods, + untransformed_rcvr_ty, + &trait_def.generics, + generics, + it.vis); // We need to do this *after* converting methods, since // convert_methods produces a tcache entry that is wrong for @@ -932,7 +881,7 @@ pub fn convert(ccx: &CrateCtxt, it: &ast::item) { write_ty_to_tcx(tcx, it.id, tpt.ty); tcx.tcache.insert(local_def(it.id), tpt); - convert_struct(ccx, rp, struct_def, generics, tpt, it.id); + convert_struct(ccx, struct_def, tpt, it.id); } ast::item_ty(_, ref generics) => { ensure_no_ty_param_bounds(ccx, it.span, generics, "type"); @@ -950,18 +899,16 @@ pub fn convert(ccx: &CrateCtxt, it: &ast::item) { } pub fn convert_struct(ccx: &CrateCtxt, - rp: Option, struct_def: &ast::struct_def, - generics: &ast::Generics, tpt: ty::ty_param_bounds_and_ty, id: ast::NodeId) { let tcx = ccx.tcx; // Write the type of each of the members for f in struct_def.fields.iter() { - convert_field(ccx, rp, tpt.generics.type_param_defs, *f, generics); + convert_field(ccx, &tpt.generics, *f); } - let (_, substs) = mk_item_substs(ccx, generics, rp, None); + let substs = mk_item_substs(ccx, &tpt.generics, None); let selfty = ty::mk_struct(tcx, local_def(id), substs); // If this struct is enum-like or tuple-like, create the type of its @@ -979,7 +926,7 @@ pub fn convert_struct(ccx: &CrateCtxt, struct_def.fields.map( |field| ccx.tcx.tcache.get( &local_def(field.node.id)).ty); - let ctor_fn_ty = ty::mk_ctor_fn(tcx, inputs, selfty); + let ctor_fn_ty = ty::mk_ctor_fn(tcx, ctor_id, inputs, selfty); write_ty_to_tcx(tcx, ctor_id, ctor_fn_ty); tcx.tcache.insert(local_def(ctor_id), ty_param_bounds_and_ty { generics: tpt.generics, @@ -1014,8 +961,6 @@ pub fn convert_foreign(ccx: &CrateCtxt, i: &ast::foreign_item) { pub fn instantiate_trait_ref(ccx: &CrateCtxt, ast_trait_ref: &ast::trait_ref, - rp: Option, - generics: &ast::Generics, self_ty: ty::t) -> @ty::TraitRef { /*! @@ -1024,9 +969,7 @@ pub fn instantiate_trait_ref(ccx: &CrateCtxt, * trait. Fails if the type is a type other than an trait type. */ - let rp = RegionParameterization::from_variance_and_generics(rp, generics); - - let rscope = TypeRscope(rp); + let rscope = ExplicitRscope; // FIXME match lookup_def_tcx(ccx.tcx, ast_trait_ref.path.span, ast_trait_ref.ref_id) { ast::DefTrait(trait_did) => { @@ -1066,14 +1009,12 @@ pub fn trait_def_of_item(ccx: &CrateCtxt, it: &ast::item) -> @ty::TraitDef { Some(&def) => return def, _ => {} } - let rp = tcx.region_paramd_items.find(&it.id).map(|x| *x); match it.node { ast::item_trait(ref generics, ref supertraits, _) => { let self_ty = ty::mk_self(tcx, def_id); - let (ty_generics, substs) = mk_item_substs(ccx, generics, rp, - Some(self_ty)); - let bounds = ensure_supertraits(ccx, it.id, it.span, rp, - *supertraits, generics); + let ty_generics = ty_generics(ccx, generics, 0); + let substs = mk_item_substs(ccx, &ty_generics, Some(self_ty)); + let bounds = ensure_supertraits(ccx, it.id, it.span, *supertraits); let trait_ref = @ty::TraitRef {def_id: def_id, substs: substs}; let trait_def = @ty::TraitDef {generics: ty_generics, @@ -1091,93 +1032,89 @@ pub fn trait_def_of_item(ccx: &CrateCtxt, it: &ast::item) -> @ty::TraitDef { } pub fn ty_of_item(ccx: &CrateCtxt, it: &ast::item) - -> ty::ty_param_bounds_and_ty { + -> ty::ty_param_bounds_and_ty { let def_id = local_def(it.id); let tcx = ccx.tcx; match tcx.tcache.find(&def_id) { - Some(&tpt) => return tpt, - _ => {} + Some(&tpt) => return tpt, + _ => {} } - let rp = tcx.region_paramd_items.find(&it.id).map(|x| *x); match it.node { - ast::item_static(ref t, _, _) => { - let typ = ccx.to_ty(&EmptyRscope, t); - let tpt = no_params(typ); - tcx.tcache.insert(local_def(it.id), tpt); - return tpt; - } - ast::item_fn(ref decl, purity, abi, ref generics, _) => { - assert!(rp.is_none()); - let ty_generics = ty_generics(ccx, None, generics, 0); - let tofd = astconv::ty_of_bare_fn(ccx, - &EmptyRscope, - purity, - abi, - &generics.lifetimes, - decl); - let tpt = ty_param_bounds_and_ty { - generics: ty::Generics { - type_param_defs: ty_generics.type_param_defs, - region_param: None - }, - ty: ty::mk_bare_fn(ccx.tcx, tofd) - }; - debug!("type of {} (id {}) is {}", - tcx.sess.str_of(it.ident), - it.id, - ppaux::ty_to_str(tcx, tpt.ty)); - ccx.tcx.tcache.insert(local_def(it.id), tpt); - return tpt; - } - ast::item_ty(ref t, ref generics) => { - match tcx.tcache.find(&local_def(it.id)) { - Some(&tpt) => return tpt, - None => { } + ast::item_static(ref t, _, _) => { + let typ = ccx.to_ty(&ExplicitRscope, t); + let tpt = no_params(typ); + tcx.tcache.insert(local_def(it.id), tpt); + return tpt; } - - let rp = tcx.region_paramd_items.find(&it.id).map(|x| *x); - let region_parameterization = - RegionParameterization::from_variance_and_generics(rp, generics); - let tpt = { - let ty = ccx.to_ty(&TypeRscope(region_parameterization), t); - ty_param_bounds_and_ty { - generics: ty_generics(ccx, rp, generics, 0), - ty: ty + ast::item_fn(ref decl, purity, abi, ref generics, _) => { + let ty_generics = ty_generics(ccx, generics, 0); + let tofd = astconv::ty_of_bare_fn(ccx, + it.id, + purity, + abi, + decl); + let tpt = ty_param_bounds_and_ty { + generics: ty::Generics { + type_param_defs: ty_generics.type_param_defs, + region_param_defs: @[], + }, + ty: ty::mk_bare_fn(ccx.tcx, tofd) + }; + debug!("type of {} (id {}) is {}", + tcx.sess.str_of(it.ident), + it.id, + ppaux::ty_to_str(tcx, tpt.ty)); + ccx.tcx.tcache.insert(local_def(it.id), tpt); + return tpt; + } + ast::item_ty(ref t, ref generics) => { + match tcx.tcache.find(&local_def(it.id)) { + Some(&tpt) => return tpt, + None => { } } - }; - tcx.tcache.insert(local_def(it.id), tpt); - return tpt; - } - ast::item_enum(_, ref generics) => { - // Create a new generic polytype. - let (ty_generics, substs) = mk_item_substs(ccx, generics, rp, None); - let t = ty::mk_enum(tcx, local_def(it.id), substs); - let tpt = ty_param_bounds_and_ty { - generics: ty_generics, - ty: t - }; - tcx.tcache.insert(local_def(it.id), tpt); - return tpt; - } - ast::item_trait(*) => { - tcx.sess.span_bug( - it.span, - format!("Invoked ty_of_item on trait")); - } - ast::item_struct(_, ref generics) => { - let (ty_generics, substs) = mk_item_substs(ccx, generics, rp, None); - let t = ty::mk_struct(tcx, local_def(it.id), substs); - let tpt = ty_param_bounds_and_ty { - generics: ty_generics, - ty: t - }; - tcx.tcache.insert(local_def(it.id), tpt); - return tpt; - } - ast::item_impl(*) | ast::item_mod(_) | - ast::item_foreign_mod(_) => fail!(), - ast::item_mac(*) => fail!("item macros unimplemented") + let tpt = { + let ty = ccx.to_ty(&ExplicitRscope, t); + ty_param_bounds_and_ty { + generics: ty_generics(ccx, generics, 0), + ty: ty + } + }; + + tcx.tcache.insert(local_def(it.id), tpt); + return tpt; + } + ast::item_enum(_, ref generics) => { + // Create a new generic polytype. + let ty_generics = ty_generics(ccx, generics, 0); + let substs = mk_item_substs(ccx, &ty_generics, None); + let t = ty::mk_enum(tcx, local_def(it.id), substs); + let tpt = ty_param_bounds_and_ty { + generics: ty_generics, + ty: t + }; + tcx.tcache.insert(local_def(it.id), tpt); + return tpt; + } + ast::item_trait(*) => { + tcx.sess.span_bug( + it.span, + format!("Invoked ty_of_item on trait")); + } + ast::item_struct(_, ref generics) => { + let ty_generics = ty_generics(ccx, generics, 0); + let substs = mk_item_substs(ccx, &ty_generics, None); + let t = ty::mk_struct(tcx, local_def(it.id), substs); + let tpt = ty_param_bounds_and_ty { + generics: ty_generics, + ty: t + }; + tcx.tcache.insert(local_def(it.id), tpt); + return tpt; + } + ast::item_impl(*) | ast::item_mod(_) | + ast::item_foreign_mod(_) => fail!(), + ast::item_mac(*) => fail!("item macros unimplemented") } } @@ -1197,28 +1134,29 @@ pub fn ty_of_foreign_item(ccx: &CrateCtxt, ty::ty_param_bounds_and_ty { generics: ty::Generics { type_param_defs: @~[], - region_param: None, + region_param_defs: @[], }, - ty: ast_ty_to_ty(ccx, &EmptyRscope, t) + ty: ast_ty_to_ty(ccx, &ExplicitRscope, t) } } } } pub fn ty_generics(ccx: &CrateCtxt, - rp: Option, generics: &ast::Generics, base_index: uint) -> ty::Generics { return ty::Generics { - region_param: rp, + region_param_defs: generics.lifetimes.iter().map(|l| { + ty::RegionParameterDef { ident: l.ident, + def_id: local_def(l.id) } + }).collect(), type_param_defs: @generics.ty_params.mapi_to_vec(|offset, param| { match ccx.tcx.ty_param_defs.find(¶m.id) { Some(&def) => def, None => { let param_ty = ty::param_ty {idx: base_index + offset, def_id: local_def(param.id)}; - let bounds = @compute_bounds(ccx, rp, generics, - param_ty, ¶m.bounds); + let bounds = @compute_bounds(ccx, param_ty, ¶m.bounds); let def = ty::TypeParameterDef { ident: param.ident, def_id: local_def(param.id), @@ -1234,13 +1172,10 @@ pub fn ty_generics(ccx: &CrateCtxt, fn compute_bounds( ccx: &CrateCtxt, - rp: Option, - generics: &ast::Generics, param_ty: ty::param_ty, ast_bounds: &OptVec) -> ty::ParamBounds { /*! - * * Translate the AST's notion of ty param bounds (which are an * enum consisting of a newtyped Ty or a region) to ty's * notion of ty param bounds, which can either be user-defined @@ -1256,7 +1191,7 @@ pub fn ty_generics(ccx: &CrateCtxt, match *ast_bound { TraitTyParamBound(ref b) => { let ty = ty::mk_param(ccx.tcx, param_ty.idx, param_ty.def_id); - let trait_ref = instantiate_trait_ref(ccx, b, rp, generics, ty); + let trait_ref = instantiate_trait_ref(ccx, b, ty); if !ty::try_add_builtin_trait( ccx.tcx, trait_ref.def_id, &mut param_bounds.builtin_bounds) @@ -1282,9 +1217,8 @@ pub fn ty_of_foreign_fn_decl(ccx: &CrateCtxt, ast_generics: &ast::Generics, abis: AbiSet) -> ty::ty_param_bounds_and_ty { - let ty_generics = ty_generics(ccx, None, ast_generics, 0); - let region_param_names = RegionParamNames::from_generics(ast_generics); - let rb = in_binding_rscope(&EmptyRscope, region_param_names); + let ty_generics = ty_generics(ccx, ast_generics, 0); + let rb = BindingRscope::new(def_id.node); let input_tys = decl.inputs.map(|a| ty_of_arg(ccx, &rb, a, None) ); let output_ty = ast_ty_to_ty(ccx, &rb, &decl.output); @@ -1293,12 +1227,10 @@ pub fn ty_of_foreign_fn_decl(ccx: &CrateCtxt, ty::BareFnTy { abis: abis, purity: ast::unsafe_fn, - sig: ty::FnSig { - bound_lifetime_names: opt_vec::Empty, - inputs: input_tys, - output: output_ty, - variadic: decl.variadic - } + sig: ty::FnSig {binder_id: def_id.node, + inputs: input_tys, + output: output_ty, + variadic: decl.variadic} }); let tpt = ty_param_bounds_and_ty { generics: ty_generics, @@ -1309,19 +1241,18 @@ pub fn ty_of_foreign_fn_decl(ccx: &CrateCtxt, } pub fn mk_item_substs(ccx: &CrateCtxt, - ast_generics: &ast::Generics, - rp: Option, - self_ty: Option) -> (ty::Generics, ty::substs) + ty_generics: &ty::Generics, + self_ty: Option) -> ty::substs { - let mut i = 0; - let ty_generics = ty_generics(ccx, rp, ast_generics, 0); - let params = ast_generics.ty_params.map_to_vec(|atp| { - let t = ty::mk_param(ccx.tcx, i, local_def(atp.id)); - i += 1u; - t - }); - let regions = rscope::bound_self_region(rp); - (ty_generics, substs {regions: ty::NonerasedRegions(regions), - self_ty: self_ty, - tps: params}) + let params: ~[ty::t] = + ty_generics.type_param_defs.iter().enumerate().map( + |(i, t)| ty::mk_param(ccx.tcx, i, t.def_id)).collect(); + + let regions: OptVec = + ty_generics.region_param_defs.iter().enumerate().map( + |(i, l)| ty::re_type_bound(l.def_id.node, i, l.ident)).collect(); + + substs {regions: ty::NonerasedRegions(regions), + self_ty: self_ty, + tps: params} } diff --git a/src/librustc/middle/typeck/infer/combine.rs b/src/librustc/middle/typeck/infer/combine.rs index 5d0f44ae7e356..d6d1618de7100 100644 --- a/src/librustc/middle/typeck/infer/combine.rs +++ b/src/librustc/middle/typeck/infer/combine.rs @@ -429,23 +429,20 @@ pub fn super_fn_sigs(this: &C, a: &ty::FnSig, b: &ty::FnSig) -> cres< return Err(ty::terr_variadic_mismatch(expected_found(this, a.variadic, b.variadic))); } - do argvecs(this, a.inputs, b.inputs) - .and_then |inputs| { - do this.tys(a.output, b.output).and_then |output| { - Ok(FnSig { - bound_lifetime_names: opt_vec::Empty, // FIXME(#4846) - inputs: inputs.clone(), - output: output, - variadic: a.variadic - }) - } - } + let inputs = if_ok!(argvecs(this, a.inputs, b.inputs)); + let output = if_ok!(this.tys(a.output, b.output)); + Ok(FnSig {binder_id: a.binder_id, + inputs: inputs, + output: output, + variadic: a.variadic}) } -pub fn super_tys( - this: &C, a: ty::t, b: ty::t) -> cres { +pub fn super_tys(this: &C, a: ty::t, b: ty::t) -> cres { let tcx = this.infcx().tcx; - return match (&ty::get(a).sty, &ty::get(b).sty) { + let a_sty = &ty::get(a).sty; + let b_sty = &ty::get(b).sty; + debug!("super_tys: a_sty={:?} b_sty={:?}", a_sty, b_sty); + return match (a_sty, b_sty) { // The "subtype" ought to be handling cases involving bot or var: (&ty::ty_bot, _) | (_, &ty::ty_bot) | @@ -494,6 +491,7 @@ pub fn super_tys( unify_float_variable(this, !this.a_is_expected(), v_id, v) } + (&ty::ty_char, _) | (&ty::ty_nil, _) | (&ty::ty_bool, _) | (&ty::ty_int(_), _) | diff --git a/src/librustc/middle/typeck/infer/glb.rs b/src/librustc/middle/typeck/infer/glb.rs index 87c7373b005d5..78e0bd17ecaa8 100644 --- a/src/librustc/middle/typeck/infer/glb.rs +++ b/src/librustc/middle/typeck/infer/glb.rs @@ -20,15 +20,13 @@ use middle::typeck::infer::to_str::InferStr; use middle::typeck::infer::{cres, InferCtxt}; use middle::typeck::infer::{TypeTrace, Subtype}; use middle::typeck::infer::fold_regions_in_sig; -use middle::typeck::isr_alist; use syntax::ast::{Many, Once, extern_fn, impure_fn, MutImmutable, MutMutable}; -use syntax::ast::{unsafe_fn}; +use syntax::ast::{unsafe_fn, NodeId}; use syntax::ast::{Onceness, purity}; +use std::hashmap::HashMap; use util::common::{indenter}; use util::ppaux::mt_to_str; -use extra::list; - pub struct Glb(CombineFields); // "greatest lower bound" (common subtype) impl Combine for Glb { @@ -132,14 +130,14 @@ impl Combine for Glb { let snapshot = self.infcx.region_vars.start_snapshot(); // Instantiate each bound region with a fresh region variable. - let (a_with_fresh, a_isr) = + let (a_with_fresh, a_map) = self.infcx.replace_bound_regions_with_fresh_regions( self.trace, a); - let a_vars = var_ids(self, a_isr); - let (b_with_fresh, b_isr) = + let a_vars = var_ids(self, &a_map); + let (b_with_fresh, b_map) = self.infcx.replace_bound_regions_with_fresh_regions( self.trace, b); - let b_vars = var_ids(self, b_isr); + let b_vars = var_ids(self, &b_map); // Collect constraints. let sig0 = if_ok!(super_fn_sigs(self, &a_with_fresh, &b_with_fresh)); @@ -152,20 +150,23 @@ impl Combine for Glb { fold_regions_in_sig( self.infcx.tcx, &sig0, - |r, _in_fn| generalize_region(self, snapshot, - new_vars, a_isr, a_vars, b_vars, - r)); + |r| generalize_region(self, snapshot, + new_vars, sig0.binder_id, + &a_map, a_vars, b_vars, + r)); debug!("sig1 = {}", sig1.inf_str(self.infcx)); return Ok(sig1); fn generalize_region(this: &Glb, snapshot: uint, new_vars: &[RegionVid], - a_isr: isr_alist, + new_binder_id: NodeId, + a_map: &HashMap, a_vars: &[RegionVid], b_vars: &[RegionVid], r0: ty::Region) -> ty::Region { if !is_var_in_set(new_vars, r0) { + assert!(!r0.is_bound()); return r0; } @@ -177,13 +178,13 @@ impl Combine for Glb { for r in tainted.iter() { if is_var_in_set(a_vars, *r) { if a_r.is_some() { - return fresh_bound_variable(this); + return fresh_bound_variable(this, new_binder_id); } else { a_r = Some(*r); } } else if is_var_in_set(b_vars, *r) { if b_r.is_some() { - return fresh_bound_variable(this); + return fresh_bound_variable(this, new_binder_id); } else { b_r = Some(*r); } @@ -192,57 +193,57 @@ impl Combine for Glb { } } - // NB---I do not believe this algorithm computes - // (necessarily) the GLB. As written it can - // spuriously fail. In particular, if there is a case - // like: &fn(fn(&a)) and fn(fn(&b)), where a and b are - // free, it will return fn(&c) where c = GLB(a,b). If - // however this GLB is not defined, then the result is - // an error, even though something like - // "fn(fn(&X))" where X is bound would be a - // subtype of both of those. - // - // The problem is that if we were to return a bound - // variable, we'd be computing a lower-bound, but not - // necessarily the *greatest* lower-bound. + // NB---I do not believe this algorithm computes + // (necessarily) the GLB. As written it can + // spuriously fail. In particular, if there is a case + // like: &fn(fn(&a)) and fn(fn(&b)), where a and b are + // free, it will return fn(&c) where c = GLB(a,b). If + // however this GLB is not defined, then the result is + // an error, even though something like + // "fn(fn(&X))" where X is bound would be a + // subtype of both of those. + // + // The problem is that if we were to return a bound + // variable, we'd be computing a lower-bound, but not + // necessarily the *greatest* lower-bound. + // + // Unfortunately, this problem is non-trivial to solve, + // because we do not know at the time of computing the GLB + // whether a GLB(a,b) exists or not, because we haven't + // run region inference (or indeed, even fully computed + // the region hierarchy!). The current algorithm seems to + // works ok in practice. if a_r.is_some() && b_r.is_some() && only_new_vars { // Related to exactly one bound variable from each fn: - return rev_lookup(this, a_isr, a_r.unwrap()); + return rev_lookup(this, a_map, new_binder_id, a_r.unwrap()); } else if a_r.is_none() && b_r.is_none() { // Not related to bound variables from either fn: + assert!(!r0.is_bound()); return r0; } else { // Other: - return fresh_bound_variable(this); + return fresh_bound_variable(this, new_binder_id); } } fn rev_lookup(this: &Glb, - a_isr: isr_alist, + a_map: &HashMap, + new_binder_id: NodeId, r: ty::Region) -> ty::Region { - let mut ret = None; - do list::each(a_isr) |pair| { - let (a_br, a_r) = *pair; - if a_r == r { - ret = Some(ty::re_bound(a_br)); - false - } else { - true + for (a_br, a_r) in a_map.iter() { + if *a_r == r { + return ty::re_fn_bound(new_binder_id, *a_br); } - }; - - match ret { - Some(x) => x, - None => this.infcx.tcx.sess.span_bug( - this.trace.origin.span(), - format!("could not find original bound region for {:?}", r)) } + this.infcx.tcx.sess.span_bug( + this.trace.origin.span(), + format!("could not find original bound region for {:?}", r)) } - fn fresh_bound_variable(this: &Glb) -> ty::Region { - this.infcx.region_vars.new_bound() + fn fresh_bound_variable(this: &Glb, binder_id: NodeId) -> ty::Region { + this.infcx.region_vars.new_bound(binder_id) } } } diff --git a/src/librustc/middle/typeck/infer/lattice.rs b/src/librustc/middle/typeck/infer/lattice.rs index 8a32a305b3a0e..9aaa4be1181f7 100644 --- a/src/librustc/middle/typeck/infer/lattice.rs +++ b/src/librustc/middle/typeck/infer/lattice.rs @@ -35,7 +35,6 @@ use middle::ty::{RegionVid, TyVar, Vid}; use middle::ty; -use middle::typeck::isr_alist; use middle::typeck::infer::*; use middle::typeck::infer::combine::*; use middle::typeck::infer::glb::Glb; @@ -43,10 +42,9 @@ use middle::typeck::infer::lub::Lub; use middle::typeck::infer::unify::*; use middle::typeck::infer::sub::Sub; use middle::typeck::infer::to_str::InferStr; +use std::hashmap::HashMap; use util::common::indenter; -use extra::list; - pub trait LatticeValue { fn sub(cf: &CombineFields, a: &Self, b: &Self) -> ures; fn lub(cf: &CombineFields, a: &Self, b: &Self) -> cres; @@ -366,14 +364,13 @@ impl TyLatticeDir for Glb { } } -pub fn super_lattice_tys( - this: &L, - a: ty::t, - b: ty::t) -> cres { +pub fn super_lattice_tys(this: &L, + a: ty::t, + b: ty::t) + -> cres { debug!("{}.lattice_tys({}, {})", this.tag(), a.inf_str(this.infcx()), b.inf_str(this.infcx())); - let _r = indenter(); if a == b { return Ok(a); @@ -524,20 +521,17 @@ pub fn lattice_var_and_t(this: &T, isr: isr_alist) -> ~[RegionVid] { - let mut result = ~[]; - do list::each(isr) |pair| { - match pair.second() { - ty::re_infer(ty::ReVar(r)) => { result.push(r); } +pub fn var_ids(this: &T, + map: &HashMap) + -> ~[RegionVid] { + map.iter().map(|(_, r)| match *r { + ty::re_infer(ty::ReVar(r)) => { r } r => { this.infcx().tcx.sess.span_bug( this.trace().origin.span(), format!("Found non-region-vid: {:?}", r)); } - } - true - }; - result + }).collect() } pub fn is_var_in_set(new_vars: &[RegionVid], r: ty::Region) -> bool { diff --git a/src/librustc/middle/typeck/infer/lub.rs b/src/librustc/middle/typeck/infer/lub.rs index 42793d956df06..ad649f379b58c 100644 --- a/src/librustc/middle/typeck/infer/lub.rs +++ b/src/librustc/middle/typeck/infer/lub.rs @@ -20,13 +20,11 @@ use middle::typeck::infer::to_str::InferStr; use middle::typeck::infer::{cres, InferCtxt}; use middle::typeck::infer::fold_regions_in_sig; use middle::typeck::infer::{TypeTrace, Subtype}; -use middle::typeck::isr_alist; -use util::ppaux::mt_to_str; - -use extra::list; -use syntax::ast::{Many, Once, extern_fn, impure_fn}; +use std::hashmap::HashMap; +use syntax::ast::{Many, Once, extern_fn, impure_fn, NodeId}; use syntax::ast::{unsafe_fn}; use syntax::ast::{Onceness, purity}; +use util::ppaux::mt_to_str; pub struct Lub(CombineFields); // least-upper-bound: common supertype @@ -125,7 +123,7 @@ impl Combine for Lub { let snapshot = self.infcx.region_vars.start_snapshot(); // Instantiate each bound region with a fresh region variable. - let (a_with_fresh, a_isr) = + let (a_with_fresh, a_map) = self.infcx.replace_bound_regions_with_fresh_regions( self.trace, a); let (b_with_fresh, _) = @@ -143,17 +141,20 @@ impl Combine for Lub { fold_regions_in_sig( self.infcx.tcx, &sig0, - |r, _in_fn| generalize_region(self, snapshot, new_vars, - a_isr, r)); + |r| generalize_region(self, snapshot, new_vars, + sig0.binder_id, &a_map, r)); return Ok(sig1); fn generalize_region(this: &Lub, snapshot: uint, new_vars: &[RegionVid], - a_isr: isr_alist, - r0: ty::Region) -> ty::Region { + new_scope: NodeId, + a_map: &HashMap, + r0: ty::Region) + -> ty::Region { // Regions that pre-dated the LUB computation stay as they are. if !is_var_in_set(new_vars, r0) { + assert!(!r0.is_bound()); debug!("generalize_region(r0={:?}): not new variable", r0); return r0; } @@ -167,6 +168,7 @@ impl Combine for Lub { debug!("generalize_region(r0={:?}): \ non-new-variables found in {:?}", r0, tainted); + assert!(!r0.is_bound()); return r0; } @@ -175,27 +177,19 @@ impl Combine for Lub { // in both A and B. Replace the variable with the "first" // bound region from A that we find it to be associated // with. - let mut ret = None; - do list::each(a_isr) |pair| { - let (a_br, a_r) = *pair; - if tainted.iter().any(|x| x == &a_r) { + for (a_br, a_r) in a_map.iter() { + if tainted.iter().any(|x| x == a_r) { debug!("generalize_region(r0={:?}): \ replacing with {:?}, tainted={:?}", - r0, a_br, tainted); - ret = Some(ty::re_bound(a_br)); - false - } else { - true + r0, *a_br, tainted); + return ty::re_fn_bound(new_scope, *a_br); } - }; - - match ret { - Some(x) => x, - None => this.infcx.tcx.sess.span_bug( - this.trace.origin.span(), - format!("Region {:?} is not associated with \ - any bound region from A!", r0)) } + + this.infcx.tcx.sess.span_bug( + this.trace.origin.span(), + format!("Region {:?} is not associated with \ + any bound region from A!", r0)) } } diff --git a/src/librustc/middle/typeck/infer/mod.rs b/src/librustc/middle/typeck/infer/mod.rs index 487eb4c32890e..121b32f4145a4 100644 --- a/src/librustc/middle/typeck/infer/mod.rs +++ b/src/librustc/middle/typeck/infer/mod.rs @@ -20,8 +20,11 @@ pub use middle::typeck::infer::resolve::{resolve_ivar, resolve_all}; pub use middle::typeck::infer::resolve::{resolve_nested_tvar}; pub use middle::typeck::infer::resolve::{resolve_rvar}; +use extra::smallintmap::SmallIntMap; use middle::ty::{TyVid, IntVid, FloatVid, RegionVid, Vid}; use middle::ty; +use middle::ty_fold; +use middle::ty_fold::TypeFolder; use middle::typeck::check::regionmanip::{replace_bound_regions_in_fn_sig}; use middle::typeck::infer::coercion::Coerce; use middle::typeck::infer::combine::{Combine, CombineFields, eq_tys}; @@ -32,19 +35,16 @@ use middle::typeck::infer::lub::Lub; use middle::typeck::infer::to_str::InferStr; use middle::typeck::infer::unify::{ValsAndBindings, Root}; use middle::typeck::infer::error_reporting::ErrorReporting; -use middle::typeck::isr_alist; -use util::common::indent; -use util::ppaux::{bound_region_to_str, ty_to_str, trait_ref_to_str, Repr, - UserString}; - +use std::hashmap::HashMap; use std::result; use std::vec; -use extra::list::Nil; -use extra::smallintmap::SmallIntMap; use syntax::ast::{MutImmutable, MutMutable}; use syntax::ast; use syntax::codemap; use syntax::codemap::Span; +use util::common::indent; +use util::ppaux::{bound_region_to_str, ty_to_str, trait_ref_to_str, Repr, + UserString}; pub mod doc; pub mod macros; @@ -225,8 +225,6 @@ pub enum RegionVariableOrigin { BoundRegionInTypeOrImpl(Span), BoundRegionInCoherence, - - BoundRegionError(Span), } pub enum fixup_err { @@ -568,15 +566,16 @@ impl InferCtxt { /// Execute `f`, unroll bindings on failure pub fn try(@mut self, f: &fn() -> Result) -> Result { debug!("try()"); - do indent { - let snapshot = self.start_snapshot(); - let r = f(); - match r { - Ok(_) => (), - Err(_) => self.rollback_to(&snapshot) + let snapshot = self.start_snapshot(); + let r = f(); + match r { + Ok(_) => { debug!("success"); } + Err(ref e) => { + debug!("error: {:?}", *e); + self.rollback_to(&snapshot) } - r } + r } /// Execute `f` then unroll any bindings it creates @@ -642,6 +641,17 @@ impl InferCtxt { ty::re_infer(ty::ReVar(self.region_vars.new_region_var(origin))) } + pub fn next_region_vars(&mut self, + origin: RegionVariableOrigin, + count: uint) + -> ~[ty::Region] { + vec::from_fn(count, |_| self.next_region_var(origin)) + } + + pub fn fresh_bound_region(&mut self, binder_id: ast::NodeId) -> ty::Region { + self.region_vars.new_bound(binder_id) + } + pub fn resolve_regions(@mut self) { let errors = self.region_vars.resolve_regions(); self.report_region_errors(&errors); // see error_reporting.rs @@ -787,9 +797,11 @@ impl InferCtxt { pub fn replace_bound_regions_with_fresh_regions(&mut self, trace: TypeTrace, fsig: &ty::FnSig) - -> (ty::FnSig, isr_alist) { - let(isr, _, fn_sig) = - replace_bound_regions_in_fn_sig(self.tcx, @Nil, None, fsig, |br| { + -> (ty::FnSig, + HashMap) { + let (map, _, fn_sig) = + replace_bound_regions_in_fn_sig(self.tcx, None, fsig, |br| { let rvar = self.next_region_var( BoundRegionInFnType(trace.origin.span(), br)); debug!("Bound region {} maps to {:?}", @@ -797,18 +809,16 @@ impl InferCtxt { rvar); rvar }); - (fn_sig, isr) + (fn_sig, map) } } pub fn fold_regions_in_sig( tcx: ty::ctxt, fn_sig: &ty::FnSig, - fldr: &fn(r: ty::Region, in_fn: bool) -> ty::Region) -> ty::FnSig + fldr: &fn(r: ty::Region) -> ty::Region) -> ty::FnSig { - do ty::fold_sig(fn_sig) |t| { - ty::fold_regions(tcx, t, |r, in_fn| fldr(r, in_fn)) - } + ty_fold::RegionFolder::regions(tcx, fldr).fold_sig(fn_sig) } impl TypeTrace { @@ -910,7 +920,6 @@ impl RegionVariableOrigin { BoundRegionInFnType(a, _) => a, BoundRegionInTypeOrImpl(a) => a, BoundRegionInCoherence => codemap::dummy_sp(), - BoundRegionError(a) => a, } } } @@ -931,7 +940,6 @@ impl Repr for RegionVariableOrigin { BoundRegionInTypeOrImpl(a) => format!("BoundRegionInTypeOrImpl({})", a.repr(tcx)), BoundRegionInCoherence => format!("BoundRegionInCoherence"), - BoundRegionError(a) => format!("BoundRegionError({})", a.repr(tcx)), } } } diff --git a/src/librustc/middle/typeck/infer/region_inference/mod.rs b/src/librustc/middle/typeck/infer/region_inference/mod.rs index 68c5ec3b7d66d..effd34da0de9d 100644 --- a/src/librustc/middle/typeck/infer/region_inference/mod.rs +++ b/src/librustc/middle/typeck/infer/region_inference/mod.rs @@ -13,7 +13,8 @@ use middle::ty; use middle::ty::{FreeRegion, Region, RegionVid}; -use middle::ty::{re_empty, re_static, re_infer, re_free, re_bound}; +use middle::ty::{re_empty, re_static, re_infer, re_free, re_type_bound, + re_fn_bound}; use middle::ty::{re_scope, ReVar, ReSkolemized, br_fresh}; use middle::typeck::infer::cres; use middle::typeck::infer::{RegionVariableOrigin, SubregionOrigin}; @@ -192,24 +193,33 @@ impl RegionVarBindings { re_infer(ReSkolemized(sc, br)) } - pub fn new_bound(&mut self) -> Region { + pub fn new_bound(&mut self, binder_id: ast::NodeId) -> Region { // Creates a fresh bound variable for use in GLB computations. // See discussion of GLB computation in the large comment at // the top of this file for more details. // - // This computation is mildly wrong in the face of rollover. - // It's conceivable, if unlikely, that one might wind up with - // accidental capture for nested functions in that case, if - // the outer function had bound regions created a very long - // time before and the inner function somehow wound up rolling - // over such that supposedly fresh identifiers were in fact - // shadowed. We should convert our bound_region - // representation to use deBruijn indices or something like - // that to eliminate that possibility. + // This computation is potentially wrong in the face of + // rollover. It's conceivable, if unlikely, that one might + // wind up with accidental capture for nested functions in + // that case, if the outer function had bound regions created + // a very long time before and the inner function somehow + // wound up rolling over such that supposedly fresh + // identifiers were in fact shadowed. For now, we just assert + // that there is no rollover -- eventually we should try to be + // robust against this possibility, either by checking the set + // of bound identifiers that appear in a given expression and + // ensure that we generate one that is distinct, or by + // changing the representation of bound regions in a fn + // declaration let sc = self.bound_count; self.bound_count += 1; - re_bound(br_fresh(sc)) + + if sc >= self.bound_count { + self.tcx.sess.bug("Rollover in RegionInference new_bound()"); + } + + re_fn_bound(binder_id, br_fresh(sc)) } pub fn add_constraint(&mut self, @@ -236,6 +246,16 @@ impl RegionVarBindings { debug!("RegionVarBindings: make_subregion({:?}, {:?})", sub, sup); match (sub, sup) { + (re_type_bound(*), _) | + (re_fn_bound(*), _) | + (_, re_type_bound(*)) | + (_, re_fn_bound(*)) => { + self.tcx.sess.span_bug( + origin.span(), + format!("Cannot relate bound region: {} <= {}", + sub.repr(self.tcx), + sup.repr(self.tcx))); + } (re_infer(ReVar(sub_id)), re_infer(ReVar(sup_id))) => { self.add_constraint(ConstrainVarSubVar(sub_id, sup_id), origin); } @@ -245,16 +265,6 @@ impl RegionVarBindings { (re_infer(ReVar(sub_id)), r) => { self.add_constraint(ConstrainVarSubReg(sub_id, r), origin); } - (re_bound(br), _) => { - self.tcx.sess.span_bug( - origin.span(), - format!("Cannot relate bound region as subregion: {:?}", br)); - } - (_, re_bound(br)) => { - self.tcx.sess.span_bug( - origin.span(), - format!("Cannot relate bound region as superregion: {:?}", br)); - } _ => { self.add_constraint(ConstrainRegSubReg(sub, sup), origin); } @@ -485,6 +495,16 @@ impl RegionVarBindings { fn lub_concrete_regions(&self, a: Region, b: Region) -> Region { match (a, b) { + (re_fn_bound(*), _) | + (_, re_fn_bound(*)) | + (re_type_bound(*), _) | + (_, re_type_bound(*)) => { + self.tcx.sess.bug( + format!("Cannot relate bound region: LUB({}, {})", + a.repr(self.tcx), + b.repr(self.tcx))); + } + (re_static, _) | (_, re_static) => { re_static // nothing lives longer than static } @@ -536,12 +556,7 @@ impl RegionVarBindings { // For these types, we cannot define any additional // relationship: (re_infer(ReSkolemized(*)), _) | - (_, re_infer(ReSkolemized(*))) | - (re_bound(_), re_bound(_)) | - (re_bound(_), re_free(_)) | - (re_bound(_), re_scope(_)) | - (re_free(_), re_bound(_)) | - (re_scope(_), re_bound(_)) => { + (_, re_infer(ReSkolemized(*))) => { if a == b {a} else {re_static} } } @@ -584,6 +599,16 @@ impl RegionVarBindings { -> cres { debug!("glb_concrete_regions({:?}, {:?})", a, b); match (a, b) { + (re_fn_bound(*), _) | + (_, re_fn_bound(*)) | + (re_type_bound(*), _) | + (_, re_type_bound(*)) => { + self.tcx.sess.bug( + format!("Cannot relate bound region: GLB({}, {})", + a.repr(self.tcx), + b.repr(self.tcx))); + } + (re_static, r) | (r, re_static) => { // static lives longer than everything else Ok(r) @@ -627,12 +652,7 @@ impl RegionVarBindings { // For these types, we cannot define any additional // relationship: (re_infer(ReSkolemized(*)), _) | - (_, re_infer(ReSkolemized(*))) | - (re_bound(_), re_bound(_)) | - (re_bound(_), re_free(_)) | - (re_bound(_), re_scope(_)) | - (re_free(_), re_bound(_)) | - (re_scope(_), re_bound(_)) => { + (_, re_infer(ReSkolemized(*))) => { if a == b { Ok(a) } else { diff --git a/src/librustc/middle/typeck/infer/resolve.rs b/src/librustc/middle/typeck/infer/resolve.rs index 564fcb76dc73b..84f3d9c69379b 100644 --- a/src/librustc/middle/typeck/infer/resolve.rs +++ b/src/librustc/middle/typeck/infer/resolve.rs @@ -50,6 +50,7 @@ use middle::ty::{FloatVar, FloatVid, IntVar, IntVid, RegionVid, TyVar, TyVid}; use middle::ty::{type_is_bot, IntType, UintType}; use middle::ty; +use middle::ty_fold; use middle::typeck::infer::{Bounds, cyclic_ty, fixup_err, fres, InferCtxt}; use middle::typeck::infer::{region_var_bound_by_region_var, unresolved_ty}; use middle::typeck::infer::to_str::InferStr; @@ -96,6 +97,20 @@ pub fn resolver(infcx: @mut InferCtxt, modes: uint) -> ResolveState { } } +impl ty_fold::TypeFolder for ResolveState { + fn tcx(&self) -> ty::ctxt { + self.infcx.tcx + } + + fn fold_ty(&mut self, t: ty::t) -> ty::t { + self.resolve_type(t) + } + + fn fold_region(&mut self, r: ty::Region) -> ty::Region { + self.resolve_region(r) + } +} + impl ResolveState { pub fn should(&mut self, mode: uint) -> bool { (self.modes & mode) == mode @@ -166,11 +181,7 @@ impl ResolveState { typ } else { self.type_depth += 1; - let result = ty::fold_regions_and_ty( - self.infcx.tcx, typ, - |r| self.resolve_region(r), - |t| self.resolve_type(t), - |t| self.resolve_type(t)); + let result = ty_fold::super_fold_ty(self, typ); self.type_depth -= 1; result } diff --git a/src/librustc/middle/typeck/infer/sub.rs b/src/librustc/middle/typeck/infer/sub.rs index e5afefe0c7164..802d635a3f0c0 100644 --- a/src/librustc/middle/typeck/infer/sub.rs +++ b/src/librustc/middle/typeck/infer/sub.rs @@ -24,8 +24,6 @@ use middle::typeck::infer::{TypeTrace, Subtype}; use util::common::{indenter}; use util::ppaux::bound_region_to_str; -use extra::list::Nil; -use extra::list; use syntax::ast::{Onceness, purity}; pub struct Sub(CombineFields); // "subtype", "subregion" etc @@ -168,9 +166,8 @@ impl Combine for Sub { // Second, we instantiate each bound region in the supertype with a // fresh concrete region. - let (skol_isr, _, b_sig) = { - do replace_bound_regions_in_fn_sig(self.infcx.tcx, @Nil, - None, b) |br| { + let (skol_map, _, b_sig) = { + do replace_bound_regions_in_fn_sig(self.infcx.tcx, None, b) |br| { let skol = self.infcx.region_vars.new_skolemized(br); debug!("Bound region {} skolemized to {:?}", bound_region_to_str(self.infcx.tcx, "", false, br), @@ -189,10 +186,7 @@ impl Combine for Sub { // that the skolemized regions do not "leak". let new_vars = self.infcx.region_vars.vars_created_since_snapshot(snapshot); - - let mut ret = Ok(sig); - do list::each(skol_isr) |pair| { - let (skol_br, skol) = *pair; + for (&skol_br, &skol) in skol_map.iter() { let tainted = self.infcx.region_vars.tainted(snapshot, skol); for tainted_region in tainted.iter() { // Each skolemized should only be relatable to itself @@ -208,19 +202,16 @@ impl Combine for Sub { // A is not as polymorphic as B: if self.a_is_expected { - ret = Err(ty::terr_regions_insufficiently_polymorphic( - skol_br, *tainted_region)); - break + return Err(ty::terr_regions_insufficiently_polymorphic( + skol_br, *tainted_region)); } else { - ret = Err(ty::terr_regions_overly_polymorphic( - skol_br, *tainted_region)); - break + return Err(ty::terr_regions_overly_polymorphic( + skol_br, *tainted_region)); } } - ret.is_ok() - }; + } - ret + return Ok(sig); } } diff --git a/src/librustc/middle/typeck/mod.rs b/src/librustc/middle/typeck/mod.rs index 75c7adfb03e40..022c0ffb43254 100644 --- a/src/librustc/middle/typeck/mod.rs +++ b/src/librustc/middle/typeck/mod.rs @@ -64,7 +64,6 @@ use extra::list; use syntax::codemap::Span; use syntax::print::pprust::*; use syntax::{ast, ast_map, abi}; -use syntax::opt_vec; pub mod check; pub mod rscope; @@ -266,7 +265,7 @@ pub fn lookup_def_ccx(ccx: &CrateCtxt, sp: Span, id: ast::NodeId) pub fn no_params(t: ty::t) -> ty::ty_param_bounds_and_ty { ty::ty_param_bounds_and_ty { generics: ty::Generics {type_param_defs: @~[], - region_param: None}, + region_param_defs: @[]}, ty: t } } @@ -354,7 +353,7 @@ fn check_main_fn_ty(ccx: &CrateCtxt, purity: ast::impure_fn, abis: abi::AbiSet::Rust(), sig: ty::FnSig { - bound_lifetime_names: opt_vec::Empty, + binder_id: main_id, inputs: ~[], output: ty::mk_nil(), variadic: false @@ -400,7 +399,7 @@ fn check_start_fn_ty(ccx: &CrateCtxt, purity: ast::impure_fn, abis: abi::AbiSet::Rust(), sig: ty::FnSig { - bound_lifetime_names: opt_vec::Empty, + binder_id: start_id, inputs: ~[ ty::mk_int(), ty::mk_imm_ptr(tcx, ty::mk_imm_ptr(tcx, ty::mk_u8())) diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index 006e14232f368..89dc71b3af648 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -11,10 +11,10 @@ use metadata::encoder; use middle::ty::{ReSkolemized, ReVar}; -use middle::ty::{bound_region, br_anon, br_named, br_self, br_cap_avoid}; +use middle::ty::{bound_region, br_anon, br_named}; use middle::ty::{br_fresh, ctxt, field}; use middle::ty::{mt, t, param_ty}; -use middle::ty::{re_bound, re_free, re_scope, re_infer, re_static, Region, +use middle::ty::{re_free, re_scope, re_infer, re_static, Region, re_empty}; use middle::ty::{ty_bool, ty_char, ty_bot, ty_box, ty_struct, ty_enum}; use middle::ty::{ty_err, ty_estr, ty_evec, ty_float, ty_bare_fn, ty_closure}; @@ -118,6 +118,11 @@ pub fn explain_region_and_span(cx: ctxt, region: ty::Region) let (msg, opt_span) = explain_span(cx, "block", blk.span); (format!("{} {}", prefix, msg), opt_span) } + Some(&ast_map::node_item(it, _)) if match it.node { + ast::item_impl(*) => true, _ => false} => { + let (msg, opt_span) = explain_span(cx, "impl", it.span); + (format!("{} {}", prefix, msg), opt_span) + } Some(_) | None => { // this really should not happen (format!("{} node {}", prefix, fr.scope_id), None) @@ -131,7 +136,7 @@ pub fn explain_region_and_span(cx: ctxt, region: ty::Region) // I believe these cases should not occur (except when debugging, // perhaps) - re_infer(_) | re_bound(_) => { + ty::re_infer(_) | ty::re_type_bound(*) | ty::re_fn_bound(*) => { (format!("lifetime {:?}", region), None) } }; @@ -154,14 +159,15 @@ pub fn bound_region_to_str(cx: ctxt, br: bound_region) -> ~str { let space_str = if space { " " } else { "" }; - if cx.sess.verbose() { return format!("{}{:?}{}", prefix, br, space_str); } + if cx.sess.verbose() { + return format!("{}{}{}", prefix, br.repr(cx), space_str); + } match br { - br_named(id) => format!("{}'{}{}", prefix, cx.sess.str_of(id), space_str), - br_self => format!("{}'self{}", prefix, space_str), + br_named(_, ident) => format!("{}'{}{}", prefix, + cx.sess.str_of(ident), space_str), br_anon(_) => prefix.to_str(), br_fresh(_) => prefix.to_str(), - br_cap_avoid(_, br) => bound_region_to_str(cx, prefix, space, *br) } } @@ -215,7 +221,7 @@ pub fn region_to_str(cx: ctxt, prefix: &str, space: bool, region: Region) -> ~st let space_str = if space { " " } else { "" }; if cx.sess.verbose() { - return format!("{}{:?}{}", prefix, region, space_str); + return format!("{}{}{}", prefix, region.repr(cx), space_str); } // These printouts are concise. They do not contain all the information @@ -223,15 +229,16 @@ pub fn region_to_str(cx: ctxt, prefix: &str, space: bool, region: Region) -> ~st // to fit that into a short string. Hence the recommendation to use // `explain_region()` or `note_and_explain_region()`. match region { - re_scope(_) => prefix.to_str(), - re_bound(br) => bound_region_to_str(cx, prefix, space, br), - re_free(ref fr) => bound_region_to_str(cx, prefix, space, fr.bound_region), - re_infer(ReSkolemized(_, br)) => { + ty::re_scope(_) => prefix.to_str(), + ty::re_type_bound(_, _, ident) => cx.sess.str_of(ident).to_owned(), + ty::re_fn_bound(_, br) => bound_region_to_str(cx, prefix, space, br), + ty::re_free(ref fr) => bound_region_to_str(cx, prefix, space, fr.bound_region), + ty::re_infer(ReSkolemized(_, br)) => { bound_region_to_str(cx, prefix, space, br) } - re_infer(ReVar(_)) => prefix.to_str(), - re_static => format!("{}'static{}", prefix, space_str), - re_empty => format!("{}'{}", prefix, space_str) + ty::re_infer(ReVar(_)) => prefix.to_str(), + ty::re_static => format!("{}'static{}", prefix, space_str), + ty::re_empty => format!("{}'{}", prefix, space_str) } } @@ -289,9 +296,10 @@ pub fn tys_to_str(cx: ctxt, ts: &[t]) -> ~str { } pub fn fn_sig_to_str(cx: ctxt, typ: &ty::FnSig) -> ~str { - format!("fn{} -> {}", - tys_to_str(cx, typ.inputs.map(|a| *a)), - ty_to_str(cx, typ.output)) + format!("fn{}{} -> {}", + typ.binder_id, + typ.inputs.repr(cx), + typ.output.repr(cx)) } pub fn trait_ref_to_str(cx: ctxt, trait_ref: &ty::TraitRef) -> ~str { @@ -594,8 +602,17 @@ impl Repr for ~[T] { impl Repr for ty::TypeParameterDef { fn repr(&self, tcx: ctxt) -> ~str { - format!("TypeParameterDef \\{{:?}, bounds: {}\\}", - self.def_id, self.bounds.repr(tcx)) + format!("TypeParameterDef({:?}, {})", + self.def_id, + self.bounds.repr(tcx)) + } +} + +impl Repr for ty::RegionParameterDef { + fn repr(&self, tcx: ctxt) -> ~str { + format!("RegionParameterDef({}, {:?})", + tcx.sess.str_of(self.ident), + self.def_id) } } @@ -655,6 +672,15 @@ impl Repr for ast::Expr { } } +impl Repr for ast::item { + fn repr(&self, tcx: ctxt) -> ~str { + format!("item({})", + ast_map::node_id_to_str(tcx.items, + self.id, + token::get_ident_interner())) + } +} + impl Repr for ast::Pat { fn repr(&self, tcx: ctxt) -> ~str { format!("pat({}: {})", @@ -665,13 +691,56 @@ impl Repr for ast::Pat { impl Repr for ty::bound_region { fn repr(&self, tcx: ctxt) -> ~str { - bound_region_ptr_to_str(tcx, *self) + match *self { + ty::br_anon(id) => format!("br_anon({})", id), + ty::br_named(id, ident) => format!("br_named({}, {})", + id.repr(tcx), + ident.repr(tcx)), + ty::br_fresh(id) => format!("br_fresh({})", id), + } } } impl Repr for ty::Region { fn repr(&self, tcx: ctxt) -> ~str { - region_to_str(tcx, "", false, *self) + match *self { + ty::re_type_bound(id, index, ident) => { + format!("re_type_bound({}, {}, {})", + id, index, ident.repr(tcx)) + } + + ty::re_fn_bound(binder_id, ref bound_region) => { + format!("re_fn_bound({}, {})", + binder_id, bound_region.repr(tcx)) + } + + ty::re_free(ref fr) => { + format!("re_free({}, {})", + fr.scope_id, + fr.bound_region.repr(tcx)) + } + + ty::re_scope(id) => { + format!("re_scope({})", id) + } + + ty::re_static => { + format!("re_static") + } + + ty::re_infer(ReVar(ref vid)) => { + format!("re_infer({})", vid.id) + } + + ty::re_infer(ReSkolemized(id, ref bound_region)) => { + format!("re_skolemized({}, {})", + id, bound_region.repr(tcx)) + } + + ty::re_empty => { + format!("re_empty") + } + } } } @@ -707,23 +776,38 @@ impl Repr for ty::ty_param_bounds_and_ty { impl Repr for ty::Generics { fn repr(&self, tcx: ctxt) -> ~str { - format!("Generics \\{type_param_defs: {}, region_param: {:?}\\}", - self.type_param_defs.repr(tcx), - self.region_param) + format!("Generics(type_param_defs: {}, region_param_defs: {})", + self.type_param_defs.repr(tcx), + self.region_param_defs.repr(tcx)) + } +} + +impl Repr for ty::ItemVariances { + fn repr(&self, tcx: ctxt) -> ~str { + format!("IterVariances(self_param={}, type_params={}, region_params={})", + self.self_param.repr(tcx), + self.type_params.repr(tcx), + self.region_params.repr(tcx)) + } +} + +impl Repr for ty::Variance { + fn repr(&self, _: ctxt) -> ~str { + self.to_str().to_owned() } } impl Repr for ty::Method { fn repr(&self, tcx: ctxt) -> ~str { - format!("method \\{ident: {}, generics: {}, transformed_self_ty: {}, \ - fty: {}, explicit_self: {}, vis: {}, def_id: {}\\}", - self.ident.repr(tcx), - self.generics.repr(tcx), - self.transformed_self_ty.repr(tcx), - self.fty.repr(tcx), - self.explicit_self.repr(tcx), - self.vis.repr(tcx), - self.def_id.repr(tcx)) + format!("method(ident: {}, generics: {}, transformed_self_ty: {}, \ + fty: {}, explicit_self: {}, vis: {}, def_id: {})", + self.ident.repr(tcx), + self.generics.repr(tcx), + self.transformed_self_ty.repr(tcx), + self.fty.repr(tcx), + self.explicit_self.repr(tcx), + self.vis.repr(tcx), + self.def_id.repr(tcx)) } } diff --git a/src/librustdoc/clean.rs b/src/librustdoc/clean.rs index dd1ad8263da86..f48ad25712d12 100644 --- a/src/librustdoc/clean.rs +++ b/src/librustdoc/clean.rs @@ -835,7 +835,7 @@ impl Clean for ast::Path { #[deriving(Clone, Encodable, Decodable)] pub struct PathSegment { name: ~str, - lifetime: Option, + lifetimes: ~[Lifetime], types: ~[Type], } @@ -843,7 +843,7 @@ impl Clean for ast::PathSegment { fn clean(&self) -> PathSegment { PathSegment { name: self.identifier.clean(), - lifetime: self.lifetime.clean(), + lifetimes: self.lifetimes.clean(), types: self.types.clean() } } diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index 9ff450d4135ff..4c64feee38439 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -92,16 +92,17 @@ impl fmt::Default for clean::Path { if i > 0 { f.buf.write("::".as_bytes()) } f.buf.write(seg.name.as_bytes()); - if seg.lifetime.is_some() || seg.types.len() > 0 { + if seg.lifetimes.len() > 0 || seg.types.len() > 0 { f.buf.write("<".as_bytes()); - match seg.lifetime { - Some(ref lifetime) => write!(f.buf, "{}", *lifetime), - None => {} + let mut comma = false; + for lifetime in seg.lifetimes.iter() { + if comma { f.buf.write(", ".as_bytes()); } + comma = true; + write!(f.buf, "{}", *lifetime); } - for (i, ty) in seg.types.iter().enumerate() { - if i > 0 || seg.lifetime.is_some() { - f.buf.write(", ".as_bytes()); - } + for ty in seg.types.iter() { + if comma { f.buf.write(", ".as_bytes()); } + comma = true; write!(f.buf, "{}", *ty); } f.buf.write(">".as_bytes()); @@ -152,16 +153,17 @@ fn path(w: &mut io::Writer, path: &clean::Path, print_all: bool, // The generics will get written to both the title and link let mut generics = ~""; let last = path.segments.last(); - if last.lifetime.is_some() || last.types.len() > 0 { + if last.lifetimes.len() > 0 || last.types.len() > 0 { + let mut counter = 0; generics.push_str("<"); - match last.lifetime { - Some(ref lifetime) => generics.push_str(format!("{}", *lifetime)), - None => {} + for lifetime in last.lifetimes.iter() { + if counter > 0 { generics.push_str(", "); } + counter += 1; + generics.push_str(format!("{}", *lifetime)); } - for (i, ty) in last.types.iter().enumerate() { - if i > 0 || last.lifetime.is_some() { - generics.push_str(", "); - } + for ty in last.types.iter() { + if counter > 0 { generics.push_str(", "); } + counter += 1; generics.push_str(format!("{}", *ty)); } generics.push_str(">"); @@ -495,7 +497,7 @@ impl fmt::Default for clean::ViewListIdent { global: false, segments: ~[clean::PathSegment { name: v.name.clone(), - lifetime: None, + lifetimes: ~[], types: ~[], }] }; diff --git a/src/libstd/at_vec.rs b/src/libstd/at_vec.rs index 7d10061e812c3..90729966c18a6 100644 --- a/src/libstd/at_vec.rs +++ b/src/libstd/at_vec.rs @@ -12,7 +12,7 @@ use clone::Clone; use container::Container; -use iter::Iterator; +use iter::{Iterator, FromIterator}; use option::{Option, Some, None}; use mem; use unstable::raw::Repr; @@ -134,6 +134,17 @@ impl Clone for @[T] { } } +impl FromIterator for @[A] { + fn from_iterator>(iterator: &mut T) -> @[A] { + let (lower, _) = iterator.size_hint(); + do build(Some(lower)) |push| { + for x in *iterator { + push(x); + } + } + } +} + #[cfg(not(test))] #[allow(missing_doc)] pub mod traits { diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index c0c2e2822f162..6245c61dfa184 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -28,7 +28,7 @@ use extra::serialize::{Encodable, Decodable, Encoder, Decoder}; // table) and a SyntaxContext to track renaming and // macro expansion per Flatt et al., "Macros // That Work Together" -#[deriving(Clone, IterBytes, ToStr)] +#[deriving(Clone, IterBytes, ToStr, TotalEq, TotalOrd)] pub struct Ident { name: Name, ctxt: SyntaxContext } impl Ident { @@ -110,6 +110,7 @@ pub enum SyntaxContext_ { /// A name is a part of an identifier, representing a string or gensym. It's /// the result of interning. pub type Name = uint; + /// A mark represents a unique id associated with a macro expansion pub type Mrk = uint; @@ -156,9 +157,8 @@ pub struct Path { pub struct PathSegment { /// The identifier portion of this path segment. identifier: Ident, - /// The lifetime parameter for this path segment. Currently only one - /// lifetime parameter is allowed. - lifetime: Option, + /// The lifetime parameters for this path segment. + lifetimes: OptVec, /// The type parameters for this path segment, if present. types: OptVec, } @@ -167,7 +167,7 @@ pub type CrateNum = int; pub type NodeId = int; -#[deriving(Clone, Eq, Encodable, Decodable, IterBytes, ToStr)] +#[deriving(Clone, TotalEq, TotalOrd, Eq, Encodable, Decodable, IterBytes, ToStr)] pub struct DefId { crate: CrateNum, node: NodeId, diff --git a/src/libsyntax/ast_map.rs b/src/libsyntax/ast_map.rs index 17613d19c7ef1..f3d7ac1804db7 100644 --- a/src/libsyntax/ast_map.rs +++ b/src/libsyntax/ast_map.rs @@ -488,3 +488,15 @@ pub fn node_item_query(items: map, id: NodeId, _ => fail!("{}", error_msg) } } + +pub fn item_span(items: map, + id: ast::NodeId) + -> Span { + match items.find(&id) { + Some(&node_item(item, _)) => item.span, + r => { + fail!(format!("item_span: expected item with id {} but found {:?}", + id, r)) + } + } +} diff --git a/src/libsyntax/ast_util.rs b/src/libsyntax/ast_util.rs index 3ec87dbdd26fb..ccae25dc012ac 100644 --- a/src/libsyntax/ast_util.rs +++ b/src/libsyntax/ast_util.rs @@ -225,7 +225,7 @@ pub fn ident_to_path(s: Span, identifier: Ident) -> Path { segments: ~[ ast::PathSegment { identifier: identifier, - lifetime: None, + lifetimes: opt_vec::Empty, types: opt_vec::Empty, } ], @@ -948,7 +948,7 @@ pub fn segments_name_eq(a : &[ast::PathSegment], b : &[ast::PathSegment]) -> boo for (idx,seg) in a.iter().enumerate() { if (seg.identifier.name != b[idx].identifier.name) // FIXME #7743: ident -> name problems in lifetime comparison? - || (seg.lifetime != b[idx].lifetime) + || (seg.lifetimes != b[idx].lifetimes) // can types contain idents? || (seg.types != b[idx].types) { return false; @@ -966,7 +966,9 @@ mod test { use std::hashmap::HashMap; fn ident_to_segment(id : &Ident) -> PathSegment { - PathSegment{identifier:id.clone(), lifetime: None, types: opt_vec::Empty} + PathSegment {identifier:id.clone(), + lifetimes: opt_vec::Empty, + types: opt_vec::Empty} } #[test] fn idents_name_eq_test() { diff --git a/src/libsyntax/ext/build.rs b/src/libsyntax/ext/build.rs index 0a5e20fc2b29a..5ae158045e0e7 100644 --- a/src/libsyntax/ext/build.rs +++ b/src/libsyntax/ext/build.rs @@ -38,7 +38,7 @@ pub trait AstBuilder { fn path_all(&self, sp: Span, global: bool, idents: ~[ast::Ident], - rp: Option, + lifetimes: OptVec, types: ~[ast::Ty]) -> ast::Path; @@ -237,19 +237,19 @@ pub trait AstBuilder { impl AstBuilder for @ExtCtxt { fn path(&self, span: Span, strs: ~[ast::Ident]) -> ast::Path { - self.path_all(span, false, strs, None, ~[]) + self.path_all(span, false, strs, opt_vec::Empty, ~[]) } fn path_ident(&self, span: Span, id: ast::Ident) -> ast::Path { self.path(span, ~[id]) } fn path_global(&self, span: Span, strs: ~[ast::Ident]) -> ast::Path { - self.path_all(span, true, strs, None, ~[]) + self.path_all(span, true, strs, opt_vec::Empty, ~[]) } fn path_all(&self, sp: Span, global: bool, mut idents: ~[ast::Ident], - rp: Option, + lifetimes: OptVec, types: ~[ast::Ty]) -> ast::Path { let last_identifier = idents.pop(); @@ -257,13 +257,13 @@ impl AstBuilder for @ExtCtxt { .map(|ident| { ast::PathSegment { identifier: ident, - lifetime: None, + lifetimes: opt_vec::Empty, types: opt_vec::Empty, } }).collect(); segments.push(ast::PathSegment { identifier: last_identifier, - lifetime: rp, + lifetimes: lifetimes, types: opt_vec::from(types), }); ast::Path { @@ -327,7 +327,7 @@ impl AstBuilder for @ExtCtxt { self.ident_of("option"), self.ident_of("Option") ], - None, + opt_vec::Empty, ~[ ty ]), None) } diff --git a/src/libsyntax/ext/concat_idents.rs b/src/libsyntax/ext/concat_idents.rs index 0ca18f1208d0d..216bc3097ce94 100644 --- a/src/libsyntax/ext/concat_idents.rs +++ b/src/libsyntax/ext/concat_idents.rs @@ -43,7 +43,7 @@ pub fn expand_syntax_ext(cx: @ExtCtxt, sp: Span, tts: &[ast::token_tree]) segments: ~[ ast::PathSegment { identifier: res, - lifetime: None, + lifetimes: opt_vec::Empty, types: opt_vec::Empty, } ] diff --git a/src/libsyntax/ext/deriving/generic.rs b/src/libsyntax/ext/deriving/generic.rs index cfb6048df18f1..b37757341efd8 100644 --- a/src/libsyntax/ext/deriving/generic.rs +++ b/src/libsyntax/ext/deriving/generic.rs @@ -375,14 +375,10 @@ impl<'self> TraitDef<'self> { cx.ty_ident(trait_span, ty_param.ident) }; - let self_lifetime = if generics.lifetimes.is_empty() { - None - } else { - Some(*generics.lifetimes.get(0)) - }; + let self_lifetimes = generics.lifetimes.clone(); // Create the type of `self`. - let self_type = cx.ty_path(cx.path_all(trait_span, false, ~[ type_ident ], self_lifetime, + let self_type = cx.ty_path(cx.path_all(trait_span, false, ~[ type_ident ], self_lifetimes, opt_vec::take_vec(self_ty_params)), None); let doc_attr = cx.attribute( diff --git a/src/libsyntax/ext/deriving/rand.rs b/src/libsyntax/ext/deriving/rand.rs index 1e2a6fa2eb51b..d014816c070c1 100644 --- a/src/libsyntax/ext/deriving/rand.rs +++ b/src/libsyntax/ext/deriving/rand.rs @@ -14,6 +14,7 @@ use codemap::Span; use ext::base::ExtCtxt; use ext::build::{AstBuilder}; use ext::deriving::generic::*; +use opt_vec; pub fn expand_deriving_rand(cx: @ExtCtxt, span: Span, @@ -77,7 +78,7 @@ fn rand_substructure(cx: @ExtCtxt, span: Span, substr: &Substructure) -> @Expr { let rand_name = cx.path_all(span, true, rand_ident.clone(), - None, + opt_vec::Empty, ~[]); let rand_name = cx.expr_path(rand_name); diff --git a/src/libsyntax/ext/deriving/ty.rs b/src/libsyntax/ext/deriving/ty.rs index c60259304aef2..d1a5af5f7e891 100644 --- a/src/libsyntax/ext/deriving/ty.rs +++ b/src/libsyntax/ext/deriving/ty.rs @@ -19,6 +19,7 @@ use ext::base::ExtCtxt; use ext::build::AstBuilder; use codemap::{Span,respan}; use opt_vec; +use opt_vec::OptVec; /// The types of pointers pub enum PtrTy<'self> { @@ -71,7 +72,7 @@ impl<'self> Path<'self> { self_generics: &Generics) -> ast::Path { let idents = self.path.map(|s| cx.ident_of(*s) ); - let lt = mk_lifetime(cx, span, &self.lifetime); + let lt = mk_lifetimes(cx, span, &self.lifetime); let tys = self.params.map(|t| t.to_ty(cx, span, self_ty, self_generics)); cx.path_all(span, self.global, idents, lt, tys) @@ -116,6 +117,13 @@ fn mk_lifetime(cx: @ExtCtxt, span: Span, lt: &Option<&str>) -> Option) -> OptVec { + match *lt { + Some(ref s) => opt_vec::with(cx.lifetime(span, cx.ident_of(*s))), + None => opt_vec::Empty + } +} + impl<'self> Ty<'self> { pub fn to_ty(&self, cx: @ExtCtxt, @@ -166,13 +174,9 @@ impl<'self> Ty<'self> { let self_params = do self_generics.ty_params.map |ty_param| { cx.ty_ident(span, ty_param.ident) }; - let lifetime = if self_generics.lifetimes.is_empty() { - None - } else { - Some(*self_generics.lifetimes.get(0)) - }; + let lifetimes = self_generics.lifetimes.clone(); - cx.path_all(span, false, ~[self_ty], lifetime, + cx.path_all(span, false, ~[self_ty], lifetimes, opt_vec::take_vec(self_params)) } Literal(ref p) => { diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index ba946d5fb1f1d..b74349da2a9fa 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -169,7 +169,7 @@ pub fn expand_expr(extsbox: @mut SyntaxEnv, segments: ~[ ast::PathSegment { identifier: ident, - lifetime: None, + lifetimes: opt_vec::Empty, types: opt_vec::Empty, } ], @@ -628,7 +628,7 @@ impl Visitor<()> for NewNameFinderContext { segments: [ ast::PathSegment { identifier: id, - lifetime: _, + lifetimes: _, types: _ } ] diff --git a/src/libsyntax/ext/format.rs b/src/libsyntax/ext/format.rs index 943279d2dc683..00919fce5db6c 100644 --- a/src/libsyntax/ext/format.rs +++ b/src/libsyntax/ext/format.rs @@ -15,7 +15,7 @@ use ext::base; use ext::build::AstBuilder; use rsparse = parse; use parse::token; - +use opt_vec; use std::fmt::parse; use std::hashmap::{HashMap, HashSet}; use std::vec; @@ -464,7 +464,7 @@ impl Context { sp, true, rtpath("Method"), - Some(life), + opt_vec::with(life), ~[] ), None); let st = ast::item_static(ty, ast::MutImmutable, method); @@ -582,7 +582,8 @@ impl Context { self.ecx.ident_of("rt"), self.ecx.ident_of("Piece"), ], - Some(self.ecx.lifetime(self.fmtsp, self.ecx.ident_of("static"))), + opt_vec::with( + self.ecx.lifetime(self.fmtsp, self.ecx.ident_of("static"))), ~[] ), None); let ty = ast::ty_fixed_length_vec( diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index 388de29b45680..ea0ab95a45105 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -144,7 +144,7 @@ pub trait ast_fold { ident: self.fold_ident(m.ident), attrs: m.attrs.map(|a| fold_attribute_(*a, self)), generics: fold_generics(&m.generics, self), - explicit_self: m.explicit_self, + explicit_self: self.fold_explicit_self(&m.explicit_self), purity: m.purity, decl: fold_fn_decl(&m.decl, self), body: self.fold_block(&m.body), @@ -245,12 +245,14 @@ pub trait ast_fold { ty_uniq(ref mt) => ty_uniq(fold_mt(mt, self)), ty_vec(ref mt) => ty_vec(fold_mt(mt, self)), ty_ptr(ref mt) => ty_ptr(fold_mt(mt, self)), - ty_rptr(region, ref mt) => ty_rptr(region, fold_mt(mt, self)), + ty_rptr(ref region, ref mt) => { + ty_rptr(fold_opt_lifetime(region, self), fold_mt(mt, self)) + } ty_closure(ref f) => { ty_closure(@TyClosure { sigil: f.sigil, purity: f.purity, - region: f.region, + region: fold_opt_lifetime(&f.region, self), onceness: f.onceness, bounds: fold_opt_bounds(&f.bounds, self), decl: fold_fn_decl(&f.decl, self), @@ -349,7 +351,7 @@ pub trait ast_fold { global: p.global, segments: p.segments.map(|segment| ast::PathSegment { identifier: self.fold_ident(segment.identifier), - lifetime: segment.lifetime, + lifetimes: segment.lifetimes.map(|l| fold_lifetime(l, self)), types: segment.types.map(|typ| self.fold_ty(typ)), }) } @@ -389,6 +391,24 @@ pub trait ast_fold { fn new_span(&self, sp: Span) -> Span { sp } + + fn fold_explicit_self(&self, es: &explicit_self) -> explicit_self { + Spanned { + span: self.new_span(es.span), + node: self.fold_explicit_self_(&es.node) + } + } + + fn fold_explicit_self_(&self, es: &explicit_self_) -> explicit_self_ { + match *es { + sty_static | sty_value(_) | sty_uniq(_) | sty_box(_) => { + *es + } + sty_region(ref lifetime, m) => { + sty_region(fold_opt_lifetime(lifetime, self), m) + } + } + } } /* some little folds that probably aren't useful to have in ast_fold itself*/ @@ -505,6 +525,11 @@ pub fn fold_lifetimes(lts: &OptVec, fld: &T) lts.map(|l| fold_lifetime(l, fld)) } +pub fn fold_opt_lifetime(o_lt: &Option, fld: &T) + -> Option { + o_lt.as_ref().map(|lt| fold_lifetime(lt, fld)) +} + pub fn fold_generics(generics: &Generics, fld: &T) -> Generics { Generics {ty_params: fold_ty_params(&generics.ty_params, fld), lifetimes: fold_lifetimes(&generics.lifetimes, fld)} @@ -675,7 +700,7 @@ pub fn noop_fold_type_method(m: &TypeMethod, fld: &T) purity: m.purity, decl: fold_fn_decl(&m.decl, fld), generics: fold_generics(&m.generics, fld), - explicit_self: m.explicit_self, + explicit_self: fld.fold_explicit_self(&m.explicit_self), id: fld.new_id(m.id), span: fld.new_span(m.span), } diff --git a/src/libsyntax/opt_vec.rs b/src/libsyntax/opt_vec.rs index 2000d0b97461f..4d39d4df72f53 100644 --- a/src/libsyntax/opt_vec.rs +++ b/src/libsyntax/opt_vec.rs @@ -165,3 +165,13 @@ impl<'self, T> Iterator<&'self T> for OptVecIterator<'self, T> { } } } + +impl FromIterator for OptVec { + fn from_iterator>(iterator: &mut T) -> OptVec { + let mut r = Empty; + for x in *iterator { + r.push(x); + } + r + } +} diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs index 6c81784b5dee4..672865aadcc26 100644 --- a/src/libsyntax/parse/mod.rs +++ b/src/libsyntax/parse/mod.rs @@ -368,7 +368,7 @@ mod test { segments: ~[ ast::PathSegment { identifier: str_to_ident("a"), - lifetime: None, + lifetimes: opt_vec::Empty, types: opt_vec::Empty, } ], @@ -387,12 +387,12 @@ mod test { segments: ~[ ast::PathSegment { identifier: str_to_ident("a"), - lifetime: None, + lifetimes: opt_vec::Empty, types: opt_vec::Empty, }, ast::PathSegment { identifier: str_to_ident("b"), - lifetime: None, + lifetimes: opt_vec::Empty, types: opt_vec::Empty, } ] @@ -592,7 +592,7 @@ mod test { segments: ~[ ast::PathSegment { identifier: str_to_ident("d"), - lifetime: None, + lifetimes: opt_vec::Empty, types: opt_vec::Empty, } ], @@ -614,7 +614,7 @@ mod test { segments: ~[ ast::PathSegment { identifier: str_to_ident("b"), - lifetime: None, + lifetimes: opt_vec::Empty, types: opt_vec::Empty, } ], @@ -641,7 +641,7 @@ mod test { segments: ~[ ast::PathSegment { identifier: str_to_ident("b"), - lifetime: None, + lifetimes: opt_vec::Empty, types: opt_vec::Empty, } ], @@ -669,7 +669,7 @@ mod test { ast::PathSegment { identifier: str_to_ident("int"), - lifetime: None, + lifetimes: opt_vec::Empty, types: opt_vec::Empty, } ], @@ -687,7 +687,7 @@ mod test { ast::PathSegment { identifier: str_to_ident("b"), - lifetime: None, + lifetimes: opt_vec::Empty, types: opt_vec::Empty, } ], @@ -724,8 +724,8 @@ mod test { identifier: str_to_ident( "b"), - lifetime: - None, + lifetimes: + opt_vec::Empty, types: opt_vec::Empty } diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 7c98d8d1c85b3..cfb4da87720be 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -1490,7 +1490,7 @@ impl Parser { segments.push(PathSegmentAndBoundSet { segment: ast::PathSegment { identifier: identifier, - lifetime: None, + lifetimes: opt_vec::Empty, types: opt_vec::Empty, }, bound_set: bound_set @@ -1499,46 +1499,21 @@ impl Parser { } // Parse the `<` before the lifetime and types, if applicable. - let (any_lifetime_or_types, optional_lifetime, types) = - if mode != NoTypesAllowed && self.eat(&token::LT) { - // Parse an optional lifetime. - let optional_lifetime = match *self.token { - token::LIFETIME(*) => Some(self.parse_lifetime()), - _ => None, - }; - - // Parse type parameters. - let mut types = opt_vec::Empty; - let mut need_comma = optional_lifetime.is_some(); - loop { - // We're done if we see a `>`. - match *self.token { - token::GT | token::BINOP(token::SHR) => { - self.expect_gt(); - break - } - _ => {} // Go on. - } - - if need_comma { - self.expect(&token::COMMA) - } else { - need_comma = true - } - - types.push(self.parse_ty(false)) + let (any_lifetime_or_types, lifetimes, types) = { + if mode != NoTypesAllowed && self.eat(&token::LT) { + let (lifetimes, types) = + self.parse_generic_values_after_lt(); + (true, lifetimes, opt_vec::from(types)) + } else { + (false, opt_vec::Empty, opt_vec::Empty) } - - (true, optional_lifetime, types) - } else { - (false, None, opt_vec::Empty) }; // Assemble and push the result. segments.push(PathSegmentAndBoundSet { segment: ast::PathSegment { identifier: identifier, - lifetime: optional_lifetime, + lifetimes: lifetimes, types: types, }, bound_set: bound_set @@ -1609,11 +1584,11 @@ impl Parser { pub fn parse_lifetime(&self) -> ast::Lifetime { match *self.token { token::LIFETIME(i) => { - let span = self.span; + let span = *self.span; self.bump(); return ast::Lifetime { id: ast::DUMMY_NODE_ID, - span: *span, + span: span, ident: i }; } @@ -4856,7 +4831,7 @@ impl Parser { segments: path.move_iter().map(|identifier| { ast::PathSegment { identifier: identifier, - lifetime: None, + lifetimes: opt_vec::Empty, types: opt_vec::Empty, } }).collect() @@ -4892,7 +4867,7 @@ impl Parser { segments: path.move_iter().map(|identifier| { ast::PathSegment { identifier: identifier, - lifetime: None, + lifetimes: opt_vec::Empty, types: opt_vec::Empty, } }).collect() @@ -4910,7 +4885,7 @@ impl Parser { segments: path.move_iter().map(|identifier| { ast::PathSegment { identifier: identifier, - lifetime: None, + lifetimes: opt_vec::Empty, types: opt_vec::Empty, } }).collect() @@ -4932,7 +4907,7 @@ impl Parser { segments: path.move_iter().map(|identifier| { ast::PathSegment { identifier: identifier, - lifetime: None, + lifetimes: opt_vec::Empty, types: opt_vec::Empty, } }).collect() diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index 08c2ae88e4fab..fd02ac68f4e1a 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -1566,13 +1566,13 @@ fn print_path_(s: @ps, } } - if segment.lifetime.is_some() || !segment.types.is_empty() { + if !segment.lifetimes.is_empty() || !segment.types.is_empty() { if colons_before_params { word(s.s, "::") } word(s.s, "<"); - for lifetime in segment.lifetime.iter() { + for lifetime in segment.lifetimes.iter() { print_lifetime(s, lifetime); if !segment.types.is_empty() { word_space(s, ",") @@ -1905,7 +1905,8 @@ pub fn print_meta_item(s: @ps, item: &ast::MetaItem) { pub fn print_view_path(s: @ps, vp: &ast::view_path) { match vp.node { ast::view_path_simple(ident, ref path, _) => { - if path.segments.last().identifier != ident { + // FIXME can't compare identifiers directly here + if path.segments.last().identifier.name != ident.name { print_ident(s, ident); space(s.s); word_space(s, "="); From 9d3f57ef0869805e0dde99cdce9548a587df7893 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 29 Oct 2013 06:08:34 -0400 Subject: [PATCH 04/16] Introduce new variance inference pass that replaces (and generalizes) old region-parameterization/variance inference. We now compute variance for type parameters but do not make use of it (most of the way towards #3598). --- src/librustc/metadata/common.rs | 2 +- src/librustc/metadata/csearch.rs | 7 +- src/librustc/metadata/decoder.rs | 8 + src/librustc/metadata/encoder.rs | 12 + src/librustc/middle/region.rs | 486 +--------- src/librustc/middle/ty.rs | 41 +- src/librustc/middle/typeck/infer/combine.rs | 173 ++-- src/librustc/middle/typeck/mod.rs | 33 +- src/librustc/middle/typeck/variance.rs | 841 ++++++++++++++++++ ...nfer-contravariance-due-to-immutability.rs | 28 - ...regions-infer-contravariance-due-to-ret.rs | 33 - .../regions-infer-covariance-due-to-arg.rs | 33 - ...ons-infer-invariance-due-to-arg-and-ret.rs | 32 - ...ns-infer-invariance-due-to-mutability-1.rs | 26 - ...ns-infer-invariance-due-to-mutability-2.rs | 26 - ...ions-infer-invariance-due-to-mutability.rs | 30 - ...ns-variance-covariant-use-contravariant.rs | 38 + ...ns-variance-invariant-use-contravariant.rs | 33 + ...egions-variance-invariant-use-covariant.rs | 27 + .../compile-fail/variance-regions-direct.rs | 73 ++ .../compile-fail/variance-regions-indirect.rs | 42 + ...ariance-contravariant-use-contravariant.rs | 32 + ...egions-variance-covariant-use-covariant.rs | 29 + 23 files changed, 1278 insertions(+), 807 deletions(-) create mode 100644 src/librustc/middle/typeck/variance.rs delete mode 100644 src/test/compile-fail/regions-infer-contravariance-due-to-immutability.rs delete mode 100644 src/test/compile-fail/regions-infer-contravariance-due-to-ret.rs delete mode 100644 src/test/compile-fail/regions-infer-covariance-due-to-arg.rs delete mode 100644 src/test/compile-fail/regions-infer-invariance-due-to-arg-and-ret.rs delete mode 100644 src/test/compile-fail/regions-infer-invariance-due-to-mutability-1.rs delete mode 100644 src/test/compile-fail/regions-infer-invariance-due-to-mutability-2.rs delete mode 100644 src/test/compile-fail/regions-infer-invariance-due-to-mutability.rs create mode 100644 src/test/compile-fail/regions-variance-covariant-use-contravariant.rs create mode 100644 src/test/compile-fail/regions-variance-invariant-use-contravariant.rs create mode 100644 src/test/compile-fail/regions-variance-invariant-use-covariant.rs create mode 100644 src/test/compile-fail/variance-regions-direct.rs create mode 100644 src/test/compile-fail/variance-regions-indirect.rs create mode 100644 src/test/run-pass/regions-variance-contravariant-use-contravariant.rs create mode 100644 src/test/run-pass/regions-variance-covariant-use-covariant.rs diff --git a/src/librustc/metadata/common.rs b/src/librustc/metadata/common.rs index 05d40bbb6aea7..5e6d0f2761523 100644 --- a/src/librustc/metadata/common.rs +++ b/src/librustc/metadata/common.rs @@ -89,7 +89,7 @@ pub static tag_path_elt_name: uint = 0x43u; pub static tag_item_field: uint = 0x44u; pub static tag_struct_mut: uint = 0x45u; -pub static tag_region_param: uint = 0x46u; +pub static tag_item_variances: uint = 0x46; pub static tag_mod_impl_trait: uint = 0x47u; /* trait items contain tag_item_trait_method elements, diff --git a/src/librustc/metadata/csearch.rs b/src/librustc/metadata/csearch.rs index 436b4c3df6bec..fdda6b38462e3 100644 --- a/src/librustc/metadata/csearch.rs +++ b/src/librustc/metadata/csearch.rs @@ -14,7 +14,6 @@ use metadata::common::*; use metadata::cstore; use metadata::decoder; -use metadata; use middle::ty; use middle::typeck; @@ -144,6 +143,12 @@ pub fn get_trait_method_def_ids(cstore: @mut cstore::CStore, decoder::get_trait_method_def_ids(cdata, def.node) } +pub fn get_item_variances(cstore: @mut cstore::CStore, + def: ast::DefId) -> ty::ItemVariances { + let cdata = cstore::get_crate_data(cstore, def.crate); + decoder::get_item_variances(cdata, def.node) +} + pub fn get_provided_trait_methods(tcx: ty::ctxt, def: ast::DefId) -> ~[@ty::Method] { diff --git a/src/librustc/metadata/decoder.rs b/src/librustc/metadata/decoder.rs index 3b4e29c97c014..b63d9320bd6e0 100644 --- a/src/librustc/metadata/decoder.rs +++ b/src/librustc/metadata/decoder.rs @@ -1088,6 +1088,14 @@ pub fn get_trait_method_def_ids(cdata: Cmd, result } +pub fn get_item_variances(cdata: Cmd, id: ast::NodeId) -> ty::ItemVariances { + let data = cdata.data; + let item_doc = lookup_item(id, data); + let variance_doc = reader::get_doc(item_doc, tag_item_variances); + let mut decoder = reader::Decoder(variance_doc); + Decodable::decode(&mut decoder) +} + pub fn get_provided_trait_methods(intr: @ident_interner, cdata: Cmd, id: ast::NodeId, tcx: ty::ctxt) -> ~[@ty::Method] { diff --git a/src/librustc/metadata/encoder.rs b/src/librustc/metadata/encoder.rs index 76c49da5861e6..9ce0b676e7e27 100644 --- a/src/librustc/metadata/encoder.rs +++ b/src/librustc/metadata/encoder.rs @@ -211,6 +211,15 @@ fn encode_region_param_defs(ebml_w: &mut writer::Encoder, } } +fn encode_item_variances(ebml_w: &mut writer::Encoder, + ecx: &EncodeContext, + id: ast::NodeId) { + let v = ty::item_variances(ecx.tcx, ast_util::local_def(id)); + ebml_w.start_tag(tag_item_variances); + v.encode(ebml_w); + ebml_w.end_tag(); +} + fn encode_bounds_and_type(ebml_w: &mut writer::Encoder, ecx: &EncodeContext, tpt: &ty::ty_param_bounds_and_ty) { @@ -992,6 +1001,7 @@ fn encode_info_for_item(ecx: &EncodeContext, ebml_w.start_tag(tag_items_data_item); encode_def_id(ebml_w, def_id); encode_family(ebml_w, 't'); + encode_item_variances(ebml_w, ecx, item.id); encode_bounds_and_type(ebml_w, ecx, &lookup_item_type(tcx, def_id)); encode_name(ecx, ebml_w, item.ident); encode_attributes(ebml_w, item.attrs); @@ -1032,6 +1042,7 @@ fn encode_info_for_item(ecx: &EncodeContext, encode_family(ebml_w, 'S'); encode_bounds_and_type(ebml_w, ecx, &lookup_item_type(tcx, def_id)); + encode_item_variances(ebml_w, ecx, item.id); encode_name(ecx, ebml_w, item.ident); encode_attributes(ebml_w, item.attrs); encode_path(ecx, ebml_w, path, ast_map::path_name(item.ident)); @@ -1138,6 +1149,7 @@ fn encode_info_for_item(ecx: &EncodeContext, ebml_w.start_tag(tag_items_data_item); encode_def_id(ebml_w, def_id); encode_family(ebml_w, 'I'); + encode_item_variances(ebml_w, ecx, item.id); let trait_def = ty::lookup_trait_def(tcx, def_id); encode_ty_type_param_defs(ebml_w, ecx, trait_def.generics.type_param_defs, diff --git a/src/librustc/middle/region.rs b/src/librustc/middle/region.rs index 29acfe1438138..80103aa410688 100644 --- a/src/librustc/middle/region.rs +++ b/src/librustc/middle/region.rs @@ -22,22 +22,14 @@ Most of the documentation on regions can be found in use driver::session::Session; -use metadata::csearch; -use middle::resolve; -use middle::ty::{region_variance, rv_covariant, rv_invariant}; -use middle::ty::{rv_contravariant, FreeRegion}; +use middle::ty::{FreeRegion}; use middle::ty; use std::hashmap::{HashMap, HashSet}; -use syntax::ast_map; use syntax::codemap::Span; -use syntax::print::pprust; -use syntax::parse::token; -use syntax::parse::token::special_idents; use syntax::{ast, visit}; use syntax::visit::{Visitor,fn_kind}; use syntax::ast::{Block,item,fn_decl,NodeId,Arm,Pat,Stmt,Expr,Local}; -use syntax::ast::{Ty,TypeMethod,struct_field}; /** The region maps encode information about region relationships. @@ -74,7 +66,6 @@ pub struct Context { struct RegionResolutionVisitor { sess: Session, - def_map: resolve::DefMap, // Generated maps: region_maps: @mut RegionMaps, @@ -504,7 +495,6 @@ impl Visitor for RegionResolutionVisitor { } pub fn resolve_crate(sess: Session, - def_map: resolve::DefMap, crate: &ast::Crate) -> @mut RegionMaps { let region_maps = @mut RegionMaps { @@ -516,483 +506,9 @@ pub fn resolve_crate(sess: Session, var_parent: None}; let mut visitor = RegionResolutionVisitor { sess: sess, - def_map: def_map, region_maps: region_maps, }; visit::walk_crate(&mut visitor, crate, cx); return region_maps; } -// ___________________________________________________________________________ -// Determining region parameterization -// -// Infers which type defns must be region parameterized---this is done -// by scanning their contents to see whether they reference a region -// type, directly or indirectly. This is a fixed-point computation. -// -// We do it in two passes. First we walk the AST and construct a map -// from each type defn T1 to other defns which make use of it. For example, -// if we have a type like: -// -// type S = *int; -// type T = S; -// -// Then there would be a map entry from S to T. During the same walk, -// we also construct add any types that reference regions to a set and -// a worklist. We can then process the worklist, propagating indirect -// dependencies until a fixed point is reached. - -pub type region_paramd_items = @mut HashMap; - -#[deriving(Eq)] -pub struct region_dep { - ambient_variance: region_variance, - id: ast::NodeId -} - -pub struct DetermineRpCtxt { - sess: Session, - ast_map: ast_map::map, - def_map: resolve::DefMap, - region_paramd_items: region_paramd_items, - dep_map: @mut HashMap, - worklist: ~[ast::NodeId], - - // the innermost enclosing item id - item_id: ast::NodeId, - - // true when we are within an item but not within a method. - // see long discussion on region_is_relevant(). - anon_implies_rp: bool, - - // encodes the context of the current type; invariant if - // mutable, covariant otherwise - ambient_variance: region_variance, -} - -pub fn join_variance(variance1: region_variance, - variance2: region_variance) - -> region_variance { - match (variance1, variance2) { - (rv_invariant, _) => {rv_invariant} - (_, rv_invariant) => {rv_invariant} - (rv_covariant, rv_contravariant) => {rv_invariant} - (rv_contravariant, rv_covariant) => {rv_invariant} - (rv_covariant, rv_covariant) => {rv_covariant} - (rv_contravariant, rv_contravariant) => {rv_contravariant} - } -} - -/// Combines the ambient variance with the variance of a -/// particular site to yield the final variance of the reference. -/// -/// Example: if we are checking function arguments then the ambient -/// variance is contravariant. If we then find a `&'r T` pointer, `r` -/// appears in a co-variant position. This implies that this -/// occurrence of `r` is contra-variant with respect to the current -/// item, and hence the function returns `rv_contravariant`. -pub fn add_variance(ambient_variance: region_variance, - variance: region_variance) - -> region_variance { - match (ambient_variance, variance) { - (rv_invariant, _) => rv_invariant, - (_, rv_invariant) => rv_invariant, - (rv_covariant, c) => c, - (c, rv_covariant) => c, - (rv_contravariant, rv_contravariant) => rv_covariant - } -} - -impl DetermineRpCtxt { - pub fn add_variance(&self, variance: region_variance) -> region_variance { - add_variance(self.ambient_variance, variance) - } - - /// Records that item `id` is region-parameterized with the - /// variance `variance`. If `id` was already parameterized, then - /// the new variance is joined with the old variance. - pub fn add_rp(&mut self, id: ast::NodeId, variance: region_variance) { - assert!(id != 0); - let old_variance = self.region_paramd_items.find(&id).map(|x| *x); - let joined_variance = match old_variance { - None => variance, - Some(v) => join_variance(v, variance) - }; - - debug!("add_rp() variance for {}: {:?} == {:?} ^ {:?}", - ast_map::node_id_to_str(self.ast_map, id, - token::get_ident_interner()), - joined_variance, old_variance, variance); - - if Some(joined_variance) != old_variance { - let region_paramd_items = self.region_paramd_items; - region_paramd_items.insert(id, joined_variance); - self.worklist.push(id); - } - } - - /// Indicates that the region-parameterization of the current item - /// is dependent on the region-parameterization of the item - /// `from`. Put another way, it indicates that the current item - /// contains a value of type `from`, so if `from` is - /// region-parameterized, so is the current item. - pub fn add_dep(&mut self, from: ast::NodeId) { - debug!("add dependency from {} -> {} ({} -> {}) with variance {:?}", - from, self.item_id, - ast_map::node_id_to_str(self.ast_map, from, - token::get_ident_interner()), - ast_map::node_id_to_str(self.ast_map, self.item_id, - token::get_ident_interner()), - self.ambient_variance); - let vec = do self.dep_map.find_or_insert_with(from) |_| { - @mut ~[] - }; - let dep = region_dep { - ambient_variance: self.ambient_variance, - id: self.item_id - }; - if !vec.iter().any(|x| x == &dep) { vec.push(dep); } - } - - // Determines whether a reference to a region that appears in the - // AST implies that the enclosing type is region-parameterized (RP). - // This point is subtle. Here are some examples to make it more - // concrete. - // - // 1. impl foo for &int { ... } - // 2. impl foo for &'self int { ... } - // 3. impl foo for bar { fn m(@self) -> &'self int { ... } } - // 4. impl foo for bar { fn m(&self) -> &'self int { ... } } - // 5. impl foo for bar { fn m(&self) -> &int { ... } } - // - // In case 1, the anonymous region is being referenced, - // but it appears in a context where the anonymous region - // resolves to self, so the impl foo is RP. - // - // In case 2, the self parameter is written explicitly. - // - // In case 3, the method refers to the region `self`, so that - // implies that the impl must be region parameterized. (If the - // type bar is not region parameterized, that is an error, because - // the self region is effectively unconstrained, but that is - // detected elsewhere). - // - // In case 4, the method refers to the region `self`, but the - // `self` region is bound by the `&self` receiver, and so this - // does not require that `bar` be RP. - // - // In case 5, the anonymous region is referenced, but it - // bound by the method, so it does not refer to self. This impl - // need not be region parameterized. - // - // Normally, & or &self implies that the enclosing item is RP. - // However, within a function, & is always bound. Within a method - // with &self type, &self is also bound. We detect those last two - // cases via flags (anon_implies_rp and self_implies_rp) that are - // true when the anon or self region implies RP. - pub fn region_is_relevant(&self, r: &Option) -> bool { - match r { - &None => { - self.anon_implies_rp - } - &Some(ref l) if l.ident == special_idents::statik => { - false - } - &Some(ref l) if l.ident == special_idents::self_ => { - true - } - &Some(_) => { - false - } - } - } - - pub fn with(@mut self, - item_id: ast::NodeId, - anon_implies_rp: bool, - f: &fn()) { - let old_item_id = self.item_id; - let old_anon_implies_rp = self.anon_implies_rp; - self.item_id = item_id; - self.anon_implies_rp = anon_implies_rp; - debug!("with_item_id({}, {})", - item_id, - anon_implies_rp); - let _i = ::util::common::indenter(); - f(); - self.item_id = old_item_id; - self.anon_implies_rp = old_anon_implies_rp; - } - - pub fn with_ambient_variance(@mut self, - variance: region_variance, - f: &fn()) { - let old_ambient_variance = self.ambient_variance; - self.ambient_variance = self.add_variance(variance); - f(); - self.ambient_variance = old_ambient_variance; - } -} - -fn determine_rp_in_item(visitor: &mut DetermineRpVisitor, - item: @ast::item) { - do visitor.cx.with(item.id, true) { - visit::walk_item(visitor, item, ()); - } -} - -fn determine_rp_in_fn(visitor: &mut DetermineRpVisitor, - fk: &visit::fn_kind, - decl: &ast::fn_decl, - body: &ast::Block, - _: Span, - _: ast::NodeId) { - let cx = visitor.cx; - do cx.with(cx.item_id, false) { - do cx.with_ambient_variance(rv_contravariant) { - for a in decl.inputs.iter() { - visitor.visit_ty(&a.ty, ()); - } - } - visitor.visit_ty(&decl.output, ()); - let generics = visit::generics_of_fn(fk); - visitor.visit_generics(&generics, ()); - visitor.visit_block(body, ()); - } -} - -fn determine_rp_in_ty_method(visitor: &mut DetermineRpVisitor, - ty_m: &ast::TypeMethod) { - let cx = visitor.cx; - do cx.with(cx.item_id, false) { - visit::walk_ty_method(visitor, ty_m, ()); - } -} - -fn determine_rp_in_ty(visitor: &mut DetermineRpVisitor, - ty: &ast::Ty) { - let cx = visitor.cx; - - // we are only interested in types that will require an item to - // be region-parameterized. if cx.item_id is zero, then this type - // is not a member of a type defn nor is it a constitutent of an - // impl etc. So we can ignore it and its components. - if cx.item_id == 0 { return; } - - // if this type directly references a region pointer like &'r ty, - // add to the worklist/set. Note that &'r ty is contravariant with - // respect to &r, because &'r ty can be used whereever a *smaller* - // region is expected (and hence is a supertype of those - // locations) - let sess = cx.sess; - match ty.node { - ast::ty_rptr(ref r, _) => { - debug!("referenced rptr type {}", - pprust::ty_to_str(ty, sess.intr())); - - if cx.region_is_relevant(r) { - let rv = cx.add_variance(rv_contravariant); - cx.add_rp(cx.item_id, rv) - } - } - - ast::ty_closure(ref f) => { - debug!("referenced fn type: {}", - pprust::ty_to_str(ty, sess.intr())); - match f.region { - Some(_) => { - if cx.region_is_relevant(&f.region) { - let rv = cx.add_variance(rv_contravariant); - cx.add_rp(cx.item_id, rv) - } - } - None => { - if f.sigil == ast::BorrowedSigil && cx.anon_implies_rp { - let rv = cx.add_variance(rv_contravariant); - cx.add_rp(cx.item_id, rv) - } - } - } - } - - _ => {} - } - - // if this references another named type, add the dependency - // to the dep_map. If the type is not defined in this crate, - // then check whether it is region-parameterized and consider - // that as a direct dependency. - match ty.node { - ast::ty_path(ref path, _, id) => { - match cx.def_map.find(&id) { - Some(&ast::DefTy(did)) | - Some(&ast::DefTrait(did)) | - Some(&ast::DefStruct(did)) => { - if did.crate == ast::LOCAL_CRATE { - if cx.region_is_relevant(&path.segments.last().lifetime) { - cx.add_dep(did.node); - } - } else { - let cstore = sess.cstore; - match csearch::get_region_param(cstore, did) { - None => {} - Some(variance) => { - debug!("reference to external, rp'd type {}", - pprust::ty_to_str(ty, sess.intr())); - if cx.region_is_relevant(&path.segments.last().lifetime) { - let rv = cx.add_variance(variance); - cx.add_rp(cx.item_id, rv) - } - } - } - } - } - _ => {} - } - } - _ => {} - } - - match ty.node { - ast::ty_box(ref mt) | ast::ty_uniq(ref mt) | ast::ty_vec(ref mt) | - ast::ty_rptr(_, ref mt) | ast::ty_ptr(ref mt) => { - visit_mt(visitor, mt); - } - - ast::ty_path(ref path, _, _) => { - // type parameters are---for now, anyway---always invariant - do cx.with_ambient_variance(rv_invariant) { - for tp in path.segments.iter().flat_map(|s| s.types.iter()) { - visitor.visit_ty(tp, ()); - } - } - } - - ast::ty_closure(@ast::TyClosure {decl: ref decl, _}) | - ast::ty_bare_fn(@ast::TyBareFn {decl: ref decl, _}) => { - // fn() binds the & region, so do not consider &T types that - // appear *inside* a fn() type to affect the enclosing item: - do cx.with(cx.item_id, false) { - // parameters are contravariant - do cx.with_ambient_variance(rv_contravariant) { - for a in decl.inputs.iter() { - visitor.visit_ty(&a.ty, ()); - } - } - visitor.visit_ty(&decl.output, ()); - } - } - - _ => { - visit::walk_ty(visitor, ty, ()); - } - } - - fn visit_mt(visitor: &mut DetermineRpVisitor, - mt: &ast::mt) { - let cx = visitor.cx; - // mutability is invariant - if mt.mutbl == ast::MutMutable { - do cx.with_ambient_variance(rv_invariant) { - visitor.visit_ty(mt.ty, ()); - } - } else { - visitor.visit_ty(mt.ty, ()); - } - } -} - -fn determine_rp_in_struct_field(visitor: &mut DetermineRpVisitor, - cm: @ast::struct_field) { - visit::walk_struct_field(visitor, cm, ()); -} - -struct DetermineRpVisitor { - cx: @mut DetermineRpCtxt -} - -impl Visitor<()> for DetermineRpVisitor { - - fn visit_fn(&mut self, fk:&fn_kind, fd:&fn_decl, - b:&Block, s:Span, n:NodeId, _:()) { - determine_rp_in_fn(self, fk, fd, b, s, n); - } - fn visit_item(&mut self, i:@item, _:()) { - determine_rp_in_item(self, i); - } - fn visit_ty(&mut self, t:&Ty, _:()) { - determine_rp_in_ty(self, t); - } - fn visit_ty_method(&mut self, t:&TypeMethod, _:()) { - determine_rp_in_ty_method(self, t); - } - fn visit_struct_field(&mut self, s:@struct_field, _:()) { - determine_rp_in_struct_field(self, s); - } - -} - -pub fn determine_rp_in_crate(sess: Session, - ast_map: ast_map::map, - def_map: resolve::DefMap, - crate: &ast::Crate) - -> region_paramd_items { - let cx = @mut DetermineRpCtxt { - sess: sess, - ast_map: ast_map, - def_map: def_map, - region_paramd_items: @mut HashMap::new(), - dep_map: @mut HashMap::new(), - worklist: ~[], - item_id: 0, - anon_implies_rp: false, - ambient_variance: rv_covariant - }; - - // Gather up the base set, worklist and dep_map - let mut visitor = DetermineRpVisitor { cx: cx }; - visit::walk_crate(&mut visitor, crate, ()); - - // Propagate indirect dependencies - // - // Each entry in the worklist is the id of an item C whose region - // parameterization has been updated. So we pull ids off of the - // worklist, find the current variance, and then iterate through - // all of the dependent items (that is, those items that reference - // C). For each dependent item D, we combine the variance of C - // with the ambient variance where the reference occurred and then - // update the region-parameterization of D to reflect the result. - { - let cx = &mut *cx; - while cx.worklist.len() != 0 { - let c_id = cx.worklist.pop(); - let c_variance = cx.region_paramd_items.get_copy(&c_id); - debug!("popped {} from worklist", c_id); - match cx.dep_map.find(&c_id) { - None => {} - Some(deps) => { - for dep in deps.iter() { - let v = add_variance(dep.ambient_variance, c_variance); - cx.add_rp(dep.id, v); - } - } - } - } - } - - debug!("{}", { - debug!("Region variance results:"); - let region_paramd_items = cx.region_paramd_items; - for (&key, &value) in region_paramd_items.iter() { - debug!("item {:?} ({}) is parameterized with variance {:?}", - key, - ast_map::node_id_to_str(ast_map, key, - token::get_ident_interner()), - value); - } - "----" - }); - - // return final set - return cx.region_paramd_items; -} diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index 66fba347acc13..a29591705844e 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -209,13 +209,19 @@ pub enum ast_ty_to_ty_cache_entry { atttce_resolved(t) /* resolved to a type, irrespective of region */ } -pub type opt_region_variance = Option; +#[deriving(Clone, Eq, Decodable, Encodable)] +pub struct ItemVariances { + self_param: Option, + type_params: OptVec, + region_params: OptVec +} #[deriving(Clone, Eq, Decodable, Encodable)] -pub enum region_variance { - rv_covariant, - rv_invariant, - rv_contravariant, +pub enum Variance { + Covariant, + Invariant, + Contravariant, + Bivariant, } #[deriving(Decodable, Encodable)] @@ -264,7 +270,6 @@ struct ctxt_ { named_region_map: @mut resolve_lifetime::NamedRegionMap, region_maps: @mut middle::region::RegionMaps, - region_paramd_items: middle::region::region_paramd_items, // Stores the types for various nodes in the AST. Note that this table // is not guaranteed to be populated until after typeck. See @@ -309,6 +314,10 @@ struct ctxt_ { provided_method_sources: @mut HashMap, supertraits: @mut HashMap, + // Maps from def-id of a type or region parameter to its + // (inferred) variance. + item_variance_map: @mut HashMap, + // A mapping from the def ID of an enum or struct type to the def ID // of the method that implements its destructor. If the type is not // present in this map, it does not have a destructor. This map is @@ -954,11 +963,11 @@ pub fn mk_ctxt(s: session::Session, amap: ast_map::map, freevars: freevars::freevar_map, region_maps: @mut middle::region::RegionMaps, - region_paramd_items: middle::region::region_paramd_items, lang_items: middle::lang_items::LanguageItems) -> ctxt { @ctxt_ { named_region_map: named_region_map, + item_variance_map: @mut HashMap::new(), diag: s.diagnostic(), interner: @mut HashMap::new(), next_id: @mut primitives::LAST_PRIMITIVE_ID, @@ -966,7 +975,6 @@ pub fn mk_ctxt(s: session::Session, sess: s, def_map: dm, region_maps: region_maps, - region_paramd_items: region_paramd_items, node_types: @mut HashMap::new(), node_type_substs: @mut HashMap::new(), trait_refs: @mut HashMap::new(), @@ -4410,6 +4418,12 @@ pub fn visitor_object_ty(tcx: ctxt, EmptyBuiltinBounds()))) } +pub fn item_variances(tcx: ctxt, item_id: ast::DefId) -> @ItemVariances { + lookup_locally_or_in_crate_store( + "item_variance_map", item_id, tcx.item_variance_map, + || @csearch::get_item_variances(tcx.cstore, item_id)) +} + /// Records a trait-to-implementation mapping. fn record_trait_implementation(tcx: ctxt, trait_def_id: DefId, @@ -4692,6 +4706,17 @@ pub fn hash_crate_independent(tcx: ctxt, t: t, local_hash: @str) -> u64 { hash.result_u64() } +impl Variance { + pub fn to_str(self) -> &'static str { + match self { + Covariant => "+", + Contravariant => "-", + Invariant => "o", + Bivariant => "*", + } + } +} + pub fn construct_parameter_environment( tcx: ctxt, self_bound: Option<@TraitRef>, diff --git a/src/librustc/middle/typeck/infer/combine.rs b/src/librustc/middle/typeck/infer/combine.rs index d6d1618de7100..c42f74864d249 100644 --- a/src/librustc/middle/typeck/infer/combine.rs +++ b/src/librustc/middle/typeck/infer/combine.rs @@ -123,76 +123,70 @@ pub trait Combine { } } - fn substs(&self, generics: &ty::Generics, as_: &ty::substs, + fn substs(&self, + item_def_id: ast::DefId, + as_: &ty::substs, bs: &ty::substs) -> cres { - fn relate_region_params( - this: &C, - generics: &ty::Generics, + fn relate_region_params(this: &C, + item_def_id: ast::DefId, a: &ty::RegionSubsts, b: &ty::RegionSubsts) - -> cres - { + -> cres { + let tcx = this.infcx().tcx; match (a, b) { - (&ty::ErasedRegions, _) | - (_, &ty::ErasedRegions) => { + (&ty::ErasedRegions, _) | (_, &ty::ErasedRegions) => { Ok(ty::ErasedRegions) } (&ty::NonerasedRegions(ref a_rs), &ty::NonerasedRegions(ref b_rs)) => { - match generics.region_param { - None => { - assert!(a_rs.is_empty()); - assert!(b_rs.is_empty()); - Ok(ty::NonerasedRegions(opt_vec::Empty)) - } - - Some(variance) => { - assert_eq!(a_rs.len(), 1); - assert_eq!(b_rs.len(), 1); - let a_r = *a_rs.get(0); - let b_r = *b_rs.get(0); - - match variance { - ty::rv_invariant => { - do eq_regions(this, a_r, b_r).then { - Ok(ty::NonerasedRegions(opt_vec::with(a_r))) - } - } - - ty::rv_covariant => { - do this.regions(a_r, b_r).and_then |r| { - Ok(ty::NonerasedRegions(opt_vec::with(r))) - } - } - - ty::rv_contravariant => { - do this.contraregions(a_r, b_r).and_then |r| { - Ok(ty::NonerasedRegions(opt_vec::with(r))) - } - } + let variances = ty::item_variances(tcx, item_def_id); + let region_params = &variances.region_params; + let num_region_params = region_params.len(); + + debug!("relate_region_params(\ + item_def_id={}, \ + a_rs={}, \ + b_rs={}, + region_params={})", + item_def_id.repr(tcx), + a_rs.repr(tcx), + b_rs.repr(tcx), + region_params.repr(tcx)); + + assert_eq!(num_region_params, a_rs.len()); + assert_eq!(num_region_params, b_rs.len()); + let mut rs = opt_vec::Empty; + for i in range(0, num_region_params) { + let a_r = *a_rs.get(i); + let b_r = *b_rs.get(i); + let variance = *region_params.get(i); + let r = match variance { + ty::Invariant => { + eq_regions(this, a_r, b_r) + .and_then(|()| Ok(a_r)) } - } + ty::Covariant => this.regions(a_r, b_r), + ty::Contravariant => this.contraregions(a_r, b_r), + ty::Bivariant => Ok(a_r), + }; + rs.push(if_ok!(r)); } + Ok(ty::NonerasedRegions(rs)) } } } - do self.tps(as_.tps, bs.tps).and_then |tps| { - do self.self_tys(as_.self_ty, bs.self_ty).and_then |self_ty| { - do relate_region_params(self, - generics, - &as_.regions, - &bs.regions).and_then |regions| { - Ok(substs { - regions: regions, - self_ty: self_ty, - tps: tps.clone() - }) - } - } - } + let tps = if_ok!(self.tps(as_.tps, bs.tps)); + let self_ty = if_ok!(self.self_tys(as_.self_ty, bs.self_ty)); + let regions = if_ok!(relate_region_params(self, + item_def_id, + &as_.regions, + &bs.regions)); + Ok(substs { regions: regions, + self_ty: self_ty, + tps: tps.clone() }) } fn bare_fn_tys(&self, a: &ty::BareFnTy, @@ -267,9 +261,11 @@ pub trait Combine { -> cres; fn regions(&self, a: ty::Region, b: ty::Region) -> cres; - fn vstores(&self, vk: ty::terr_vstore_kind, - a: ty::vstore, b: ty::vstore) -> cres { - + fn vstores(&self, + vk: ty::terr_vstore_kind, + a: ty::vstore, + b: ty::vstore) + -> cres { debug!("{}.vstores(a={:?}, b={:?})", self.tag(), a, b); match (a, b) { @@ -293,8 +289,7 @@ pub trait Combine { vk: ty::terr_vstore_kind, a: ty::TraitStore, b: ty::TraitStore) - -> cres { - + -> cres { debug!("{}.trait_stores(a={:?}, b={:?})", self.tag(), a, b); match (a, b) { @@ -317,7 +312,8 @@ pub trait Combine { fn trait_refs(&self, a: &ty::TraitRef, - b: &ty::TraitRef) -> cres { + b: &ty::TraitRef) + -> cres { // Different traits cannot be related // - NOTE in the future, expand out subtraits! @@ -326,15 +322,9 @@ pub trait Combine { Err(ty::terr_traits( expected_found(self, a.def_id, b.def_id))) } else { - let tcx = self.infcx().tcx; - let trait_def = ty::lookup_trait_def(tcx, a.def_id); - let substs = if_ok!(self.substs(&trait_def.generics, - &a.substs, - &b.substs)); - Ok(ty::TraitRef { - def_id: a.def_id, - substs: substs - }) + let substs = if_ok!(self.substs(a.def_id, &a.substs, &b.substs)); + Ok(ty::TraitRef { def_id: a.def_id, + substs: substs }) } } } @@ -366,8 +356,8 @@ pub fn eq_tys(this: &C, a: ty::t, b: ty::t) -> ures { pub fn eq_regions(this: &C, a: ty::Region, b: ty::Region) -> ures { debug!("eq_regions({}, {})", - a.inf_str(this.infcx()), - b.inf_str(this.infcx())); + a.repr(this.infcx().tcx), + b.repr(this.infcx().tcx)); let sub = this.sub(); do indent { this.infcx().try(|| { @@ -511,36 +501,30 @@ pub fn super_tys(this: &C, a: ty::t, b: ty::t) -> cres { (&ty::ty_enum(a_id, ref a_substs), &ty::ty_enum(b_id, ref b_substs)) if a_id == b_id => { - let type_def = ty::lookup_item_type(tcx, a_id); - do this.substs(&type_def.generics, a_substs, b_substs).and_then |substs| { - Ok(ty::mk_enum(tcx, a_id, substs)) - } + let substs = if_ok!(this.substs(a_id, + a_substs, + b_substs)); + Ok(ty::mk_enum(tcx, a_id, substs)) } (&ty::ty_trait(a_id, ref a_substs, a_store, a_mutbl, a_bounds), &ty::ty_trait(b_id, ref b_substs, b_store, b_mutbl, b_bounds)) if a_id == b_id && a_mutbl == b_mutbl => { - let trait_def = ty::lookup_trait_def(tcx, a_id); - do this.substs(&trait_def.generics, a_substs, b_substs).and_then |substs| { - do this.trait_stores(ty::terr_trait, a_store, b_store).and_then |s| { - do this.bounds(a_bounds, b_bounds).and_then |bounds| { - Ok(ty::mk_trait(tcx, - a_id, - substs.clone(), - s, - a_mutbl, - bounds)) - } - } - } + let substs = if_ok!(this.substs(a_id, a_substs, b_substs)); + let s = if_ok!(this.trait_stores(ty::terr_trait, a_store, b_store)); + let bounds = if_ok!(this.bounds(a_bounds, b_bounds)); + Ok(ty::mk_trait(tcx, + a_id, + substs.clone(), + s, + a_mutbl, + bounds)) } (&ty::ty_struct(a_id, ref a_substs), &ty::ty_struct(b_id, ref b_substs)) if a_id == b_id => { - let type_def = ty::lookup_item_type(tcx, a_id); - do this.substs(&type_def.generics, a_substs, b_substs).and_then |substs| { - Ok(ty::mk_struct(tcx, a_id, substs)) - } + let substs = if_ok!(this.substs(a_id, a_substs, b_substs)); + Ok(ty::mk_struct(tcx, a_id, substs)) } (&ty::ty_box(ref a_mt), &ty::ty_box(ref b_mt)) => { @@ -576,9 +560,8 @@ pub fn super_tys(this: &C, a: ty::t, b: ty::t) -> cres { } (&ty::ty_estr(vs_a), &ty::ty_estr(vs_b)) => { - do this.vstores(ty::terr_str, vs_a, vs_b).and_then |vs| { - Ok(ty::mk_estr(tcx,vs)) - } + let vs = if_ok!(this.vstores(ty::terr_str, vs_a, vs_b)); + Ok(ty::mk_estr(tcx,vs)) } (&ty::ty_tup(ref as_), &ty::ty_tup(ref bs)) => { diff --git a/src/librustc/middle/typeck/mod.rs b/src/librustc/middle/typeck/mod.rs index 022c0ffb43254..ed6c810e52cd6 100644 --- a/src/librustc/middle/typeck/mod.rs +++ b/src/librustc/middle/typeck/mod.rs @@ -19,16 +19,23 @@ The type checker is responsible for: 3. Guaranteeing that most type rules are met ("most?", you say, "why most?" Well, dear reader, read on) -The main entry point is `check_crate()`. Type checking operates in two major -phases: collect and check. The collect phase passes over all items and -determines their type, without examining their "innards". The check phase -then checks function bodies and so forth. +The main entry point is `check_crate()`. Type checking operates in +several major phases: -Within the check phase, we check each function body one at a time (bodies of -function expressions are checked as part of the containing function). -Inference is used to supply types wherever they are unknown. The actual -checking of a function itself has several phases (check, regionck, writeback), -as discussed in the documentation for the `check` module. +1. The collect phase first passes over all items and determines their + type, without examining their "innards". + +2. Variance inference then runs to compute the variance of each parameter + +3. Coherence checks for overlapping or orphaned impls + +4. Finally, the check phase then checks function bodies and so forth. + Within the check phase, we check each function body one at a time + (bodies of function expressions are checked as part of the + containing function). Inference is used to supply types wherever + they are unknown. The actual checking of a function itself has + several phases (check, regionck, writeback), as discussed in the + documentation for the `check` module. The type checker is defined into various submodules which are documented independently: @@ -39,6 +46,10 @@ independently: - collect: computes the types of each top-level item and enters them into the `cx.tcache` table for later use +- coherence: enforces coherence rules, builds some tables + +- variance: variance inference + - check: walks over function bodies and type checks them, inferring types for local variables, type parameters, etc as necessary. @@ -71,6 +82,7 @@ pub mod astconv; pub mod infer; pub mod collect; pub mod coherence; +pub mod variance; #[deriving(Clone, Encodable, Decodable, Eq, Ord)] pub enum param_index { @@ -455,6 +467,9 @@ pub fn check_crate(tcx: ty::ctxt, // have valid types and not error tcx.sess.abort_if_errors(); + time(time_passes, "variance inference", (), |_| + variance::infer_variance(tcx, crate)); + time(time_passes, "coherence checking", (), |_| coherence::check_coherence(ccx, crate)); diff --git a/src/librustc/middle/typeck/variance.rs b/src/librustc/middle/typeck/variance.rs new file mode 100644 index 0000000000000..adb05d252e64c --- /dev/null +++ b/src/librustc/middle/typeck/variance.rs @@ -0,0 +1,841 @@ +// Copyright 2012 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. + +/*! + +This file infers the variance of type and lifetime parameters. The +algorithm is taken from Section 4 of the paper "Taming the Wildcards: +Combining Definition- and Use-Site Variance" published in PLDI'11 and +written by Altidor et al., and hereafter referred to as The Paper. + +The basic idea is quite straightforward. We iterate over the types +defined and, for each use of a type parameter X, accumulate a +constraint indicating that the variance of X must be valid for the +variance of that use site. We then iteratively refine the variance of +X until all constraints are met. There is *always* a sol'n, because at +the limit we can declare all type parameters to be invariant and all +constriants will be satisfied. + +As a simple example, consider: + + enum Option { Some(A), None } + enum OptionalFn { Some(&fn(B)), None } + enum OptionalMap { Some(&fn(C) -> C), None } + +Here, we will generate the constraints: + + 1. V(A) <= + + 2. V(B) <= - + 3. V(C) <= + + 4. V(C) <= - + +These indicate that (1) the variance of A must be at most covariant; +(2) the variance of B must be at most contravariant; and (3, 4) the +variance of C must be at most covariant *and* contravariant. All of these +results are based on a variance lattice defined as follows: + + * Top (bivariant) + - + + o Bottom (invariant) + +Based on this lattice, the solution V(A)=+, V(B)=-, V(C)=o is the +minimal solution (which is what we are looking for; the maximal +solution is just that all variables are invariant. Not so exciting.). + +You may be wondering why fixed-point iteration is required. The reason +is that the variance of a use site may itself be a function of the +variance of other type parameters. In full generality, our constraints +take the form: + + V(X) <= Term + Term := + | - | * | o | V(X) | Term x Term + +Here the notation V(X) indicates the variance of a type/region +parameter `X` with respect to its defining class. `Term x Term` +represents the "variance transform" as defined in the paper -- `V1 x +V2` is the resulting variance when a use site with variance V2 appears +inside a use site with variance V1. + +*/ + +use std::hashmap::HashMap; +use extra::arena; +use extra::arena::Arena; +use middle::ty; +use std::vec; +use syntax::ast; +use syntax::ast_map; +use syntax::ast_util; +use syntax::parse::token; +use syntax::opt_vec; +use syntax::visit; +use syntax::visit::Visitor; + +pub fn infer_variance(tcx: ty::ctxt, + crate: &ast::Crate) { + let mut arena = arena::Arena::new(); + let terms_cx = determine_parameters_to_be_inferred(tcx, &mut arena, crate); + let constraints_cx = add_constraints_from_crate(terms_cx, crate); + solve_constraints(constraints_cx); +} + +/************************************************************************** + * Representing terms + * + * Terms are structured as a straightforward tree. Rather than rely on + * GC, we allocate terms out of a bounded arena (the lifetime of this + * arena is the lifetime 'self that is threaded around). + * + * We assign a unique index to each type/region parameter whose variance + * is to be inferred. We refer to such variables as "inferreds". An + * `InferredIndex` is a newtype'd int representing the index of such + * a variable. + */ + +type VarianceTermPtr<'self> = &'self VarianceTerm<'self>; + +struct InferredIndex(uint); + +enum VarianceTerm<'self> { + ConstantTerm(ty::Variance), + TransformTerm(VarianceTermPtr<'self>, VarianceTermPtr<'self>), + InferredTerm(InferredIndex), +} + +impl<'self> ToStr for VarianceTerm<'self> { + fn to_str(&self) -> ~str { + match *self { + ConstantTerm(c1) => format!("{}", c1.to_str()), + TransformTerm(v1, v2) => format!("({} \u00D7 {})", + v1.to_str(), v2.to_str()), + InferredTerm(id) => format!("[{}]", *id) + } + } +} + +/************************************************************************** + * The first pass over the crate simply builds up the set of inferreds. + */ + +struct TermsContext<'self> { + tcx: ty::ctxt, + arena: &'self Arena, + + // Maps from the node id of a type/generic parameter to the + // corresponding inferred index. + inferred_map: HashMap, + inferred_infos: ~[InferredInfo<'self>], +} + +enum ParamKind { TypeParam, RegionParam, SelfParam } + +struct InferredInfo<'self> { + item_id: ast::NodeId, + kind: ParamKind, + index: uint, + param_id: ast::NodeId, + term: VarianceTermPtr<'self>, +} + +fn determine_parameters_to_be_inferred<'a>(tcx: ty::ctxt, + arena: &'a mut Arena, + crate: &ast::Crate) + -> TermsContext<'a> { + let mut terms_cx = TermsContext { + tcx: tcx, + arena: arena, + inferred_map: HashMap::new(), + inferred_infos: ~[], + }; + + visit::walk_crate(&mut terms_cx, crate, ()); + + terms_cx +} + +impl<'self> TermsContext<'self> { + fn add_inferred(&mut self, + item_id: ast::NodeId, + kind: ParamKind, + index: uint, + param_id: ast::NodeId) { + let inf_index = InferredIndex(self.inferred_infos.len()); + let term = self.arena.alloc(|| InferredTerm(inf_index)); + self.inferred_infos.push(InferredInfo { item_id: item_id, + kind: kind, + index: index, + param_id: param_id, + term: term }); + let newly_added = self.inferred_map.insert(param_id, inf_index); + assert!(newly_added); + + debug!("add_inferred(item_id={}, \ + kind={:?}, \ + index={}, \ + param_id={}, + inf_index={:?})", + item_id, kind, index, param_id, inf_index); + } + + fn num_inferred(&self) -> uint { + self.inferred_infos.len() + } +} + +impl<'self> Visitor<()> for TermsContext<'self> { + fn visit_item(&mut self, + item: @ast::item, + (): ()) { + debug!("add_inferreds for item {}", item.repr(self.tcx)); + + let inferreds_on_entry = self.num_inferred(); + + // NB: In the code below for writing the results back into the + // tcx, we rely on the fact that all inferreds for a particular + // item are assigned continuous indices. + match item.node { + ast::item_trait(*) => { + self.add_inferred(item.id, SelfParam, 0, item.id); + } + _ => { } + } + + match item.node { + ast::item_enum(_, ref generics) | + ast::item_struct(_, ref generics) | + ast::item_trait(ref generics, _, _) => { + for (i, p) in generics.lifetimes.iter().enumerate() { + self.add_inferred(item.id, RegionParam, i, p.id); + } + for (i, p) in generics.ty_params.iter().enumerate() { + self.add_inferred(item.id, TypeParam, i, p.id); + } + + // If this item has no type or lifetime parameters, + // then there are no variances to infer, so just + // insert an empty entry into the variance map. + // Arguably we could just leave the map empty in this + // case but it seems cleaner to be able to distinguish + // "invalid item id" from "item id with no + // parameters". + if self.num_inferred() == inferreds_on_entry { + let newly_added = self.tcx.item_variance_map.insert( + ast_util::local_def(item.id), + @ty::ItemVariances { + self_param: None, + type_params: opt_vec::Empty, + region_params: opt_vec::Empty + }); + assert!(newly_added); + } + + visit::walk_item(self, item, ()); + } + + ast::item_impl(*) | + ast::item_static(*) | + ast::item_fn(*) | + ast::item_mod(*) | + ast::item_foreign_mod(*) | + ast::item_ty(*) | + ast::item_mac(*) => { + visit::walk_item(self, item, ()); + } + } + } +} + +/************************************************************************** + * Constraint construction and representation + * + * The second pass over the AST determines the set of constraints. + * We walk the set of items and, for each member, generate new constraints. + */ + +struct ConstraintContext<'self> { + terms_cx: TermsContext<'self>, + + covariant: VarianceTermPtr<'self>, + contravariant: VarianceTermPtr<'self>, + invariant: VarianceTermPtr<'self>, + bivariant: VarianceTermPtr<'self>, + + constraints: ~[Constraint<'self>], +} + +/// Declares that the variable `decl_id` appears in a location with +/// variance `variance`. +struct Constraint<'self> { + inferred: InferredIndex, + variance: &'self VarianceTerm<'self>, +} + +fn add_constraints_from_crate<'a>(terms_cx: TermsContext<'a>, + crate: &ast::Crate) + -> ConstraintContext<'a> { + let covariant = terms_cx.arena.alloc(|| ConstantTerm(ty::Covariant)); + let contravariant = terms_cx.arena.alloc(|| ConstantTerm(ty::Contravariant)); + let invariant = terms_cx.arena.alloc(|| ConstantTerm(ty::Invariant)); + let bivariant = terms_cx.arena.alloc(|| ConstantTerm(ty::Bivariant)); + let mut constraint_cx = ConstraintContext { + terms_cx: terms_cx, + covariant: covariant, + contravariant: contravariant, + invariant: invariant, + bivariant: bivariant, + constraints: ~[], + }; + visit::walk_crate(&mut constraint_cx, crate, ()); + constraint_cx +} + +impl<'self> Visitor<()> for ConstraintContext<'self> { + fn visit_item(&mut self, + item: @ast::item, + (): ()) { + let did = ast_util::local_def(item.id); + let tcx = self.terms_cx.tcx; + + match item.node { + ast::item_enum(ref enum_definition, _) => { + // Hack: If we directly call `ty::enum_variants`, it + // annoyingly takes it upon itself to run off and + // evaluate the discriminants eagerly (*grumpy* that's + // not the typical pattern). This results in double + // error messagees because typeck goes off and does + // this at a later time. All we really care about is + // the types of the variant arguments, so we just call + // `ty::VariantInfo::from_ast_variant()` ourselves + // here, mainly so as to mask the differences between + // struct-like enums and so forth. + for ast_variant in enum_definition.variants.iter() { + let variant = + ty::VariantInfo::from_ast_variant(tcx, + ast_variant, + /*discrimant*/ 0); + for &arg_ty in variant.args.iter() { + self.add_constraints_from_ty(arg_ty, self.covariant); + } + } + } + + ast::item_struct(*) => { + let struct_fields = ty::lookup_struct_fields(tcx, did); + for field_info in struct_fields.iter() { + assert_eq!(field_info.id.crate, ast::LOCAL_CRATE); + let field_ty = ty::node_id_to_type(tcx, field_info.id.node); + self.add_constraints_from_ty(field_ty, self.covariant); + } + } + + ast::item_trait(*) => { + let methods = ty::trait_methods(tcx, did); + for method in methods.iter() { + match method.transformed_self_ty { + Some(self_ty) => { + // The self type is a parameter, so its type + // should be considered contravariant: + self.add_constraints_from_ty( + self_ty, self.contravariant); + } + None => {} + } + + self.add_constraints_from_sig( + &method.fty.sig, self.covariant); + } + } + + ast::item_static(*) | + ast::item_fn(*) | + ast::item_mod(*) | + ast::item_foreign_mod(*) | + ast::item_ty(*) | + ast::item_impl(*) | + ast::item_mac(*) => { + visit::walk_item(self, item, ()); + } + } + } +} + +impl<'self> ConstraintContext<'self> { + fn tcx(&self) -> ty::ctxt { + self.terms_cx.tcx + } + + fn inferred_index(&self, param_id: ast::NodeId) -> InferredIndex { + match self.terms_cx.inferred_map.find(¶m_id) { + Some(&index) => index, + None => { + self.tcx().sess.bug(format!( + "No inferred index entry for {}", + ast_map::node_id_to_str(self.tcx().items, + param_id, + token::get_ident_interner()))); + } + } + } + + fn declared_variance(&self, + param_def_id: ast::DefId, + item_def_id: ast::DefId, + kind: ParamKind, + index: uint) + -> VarianceTermPtr<'self> { + /*! + * Returns a variance term representing the declared variance of + * the type/region parameter with the given id. + */ + + assert_eq!(param_def_id.crate, item_def_id.crate); + if param_def_id.crate == ast::LOCAL_CRATE { + // Parameter on an item defined within current crate: + // variance not yet inferred, so return a symbolic + // variance. + let index = self.inferred_index(param_def_id.node); + self.terms_cx.inferred_infos[*index].term + } else { + // Parameter on an item defined within another crate: + // variance already inferred, just look it up. + let variances = ty::item_variances(self.tcx(), item_def_id); + let variance = match kind { + SelfParam => variances.self_param.unwrap(), + TypeParam => *variances.type_params.get(index), + RegionParam => *variances.region_params.get(index), + }; + self.constant_term(variance) + } + } + + fn add_constraint(&mut self, + index: InferredIndex, + variance: VarianceTermPtr<'self>) { + debug!("add_constraint(index={}, variance={})", + *index, variance.to_str()); + self.constraints.push(Constraint { inferred: index, + variance: variance }); + } + + fn contravariant(&mut self, + variance: VarianceTermPtr<'self>) + -> VarianceTermPtr<'self> { + self.xform(variance, self.contravariant) + } + + fn invariant(&mut self, + variance: VarianceTermPtr<'self>) + -> VarianceTermPtr<'self> { + self.xform(variance, self.invariant) + } + + fn constant_term(&self, v: ty::Variance) -> VarianceTermPtr<'self> { + match v { + ty::Covariant => self.covariant, + ty::Invariant => self.invariant, + ty::Contravariant => self.contravariant, + ty::Bivariant => self.bivariant, + } + } + + fn xform(&mut self, + v1: VarianceTermPtr<'self>, + v2: VarianceTermPtr<'self>) + -> VarianceTermPtr<'self> { + match (*v1, *v2) { + (_, ConstantTerm(ty::Covariant)) => { + // Applying a "covariant" transform is always a no-op + v1 + } + + (ConstantTerm(c1), ConstantTerm(c2)) => { + self.constant_term(c1.xform(c2)) + } + + _ => { + self.terms_cx.arena.alloc(|| TransformTerm(v1, v2)) + } + } + } + + fn add_constraints_from_ty(&mut self, + ty: ty::t, + variance: VarianceTermPtr<'self>) { + debug!("add_constraints_from_ty(ty={})", ty.repr(self.tcx())); + + match ty::get(ty).sty { + ty::ty_nil | ty::ty_bot | ty::ty_bool | + ty::ty_char | ty::ty_int(_) | ty::ty_uint(_) | + ty::ty_float(_) => { + /* leaf type -- noop */ + } + + ty::ty_rptr(region, ref mt) => { + let contra = self.contravariant(variance); + self.add_constraints_from_region(region, contra); + self.add_constraints_from_mt(mt, variance); + } + + ty::ty_estr(vstore) => { + self.add_constraints_from_vstore(vstore, variance); + } + + ty::ty_evec(ref mt, vstore) => { + self.add_constraints_from_vstore(vstore, variance); + self.add_constraints_from_mt(mt, variance); + } + + ty::ty_box(ref mt) | + ty::ty_uniq(ref mt) | + ty::ty_ptr(ref mt) => { + self.add_constraints_from_mt(mt, variance); + } + + ty::ty_tup(ref subtys) => { + for &subty in subtys.iter() { + self.add_constraints_from_ty(subty, variance); + } + } + + ty::ty_enum(def_id, ref substs) | + ty::ty_struct(def_id, ref substs) => { + let item_type = ty::lookup_item_type(self.tcx(), def_id); + self.add_constraints_from_substs(def_id, &item_type.generics, + substs, variance); + } + + ty::ty_trait(def_id, ref substs, _, _, _) => { + let trait_def = ty::lookup_trait_def(self.tcx(), def_id); + self.add_constraints_from_substs(def_id, &trait_def.generics, + substs, variance); + } + + ty::ty_param(ty::param_ty { def_id: ref def_id, _ }) => { + assert_eq!(def_id.crate, ast::LOCAL_CRATE); + match self.terms_cx.inferred_map.find(&def_id.node) { + Some(&index) => { + self.add_constraint(index, variance); + } + None => { + // We do not infer variance for type parameters + // declared on methods. They will not be present + // in the inferred_map. + } + } + } + + ty::ty_self(ref def_id) => { + assert_eq!(def_id.crate, ast::LOCAL_CRATE); + let index = self.inferred_index(def_id.node); + self.add_constraint(index, variance); + } + + ty::ty_bare_fn(ty::BareFnTy { sig: ref sig, _ }) => { + self.add_constraints_from_sig(sig, variance); + } + + ty::ty_closure(ty::ClosureTy { sig: ref sig, region, _ }) => { + let contra = self.contravariant(variance); + self.add_constraints_from_region(region, contra); + self.add_constraints_from_sig(sig, variance); + } + + ty::ty_infer(*) | ty::ty_err | ty::ty_type | + ty::ty_opaque_box | ty::ty_opaque_closure_ptr(*) | + ty::ty_unboxed_vec(*) => { + self.tcx().sess.bug( + format!("Unexpected type encountered in \ + variance inference: {}", + ty.repr(self.tcx()))); + } + } + } + + fn add_constraints_from_vstore(&mut self, + vstore: ty::vstore, + variance: VarianceTermPtr<'self>) { + match vstore { + ty::vstore_slice(r) => { + let contra = self.contravariant(variance); + self.add_constraints_from_region(r, contra); + } + + ty::vstore_fixed(_) | ty::vstore_uniq | ty::vstore_box => { + } + } + } + + fn add_constraints_from_substs(&mut self, + def_id: ast::DefId, + generics: &ty::Generics, + substs: &ty::substs, + variance: VarianceTermPtr<'self>) { + debug!("add_constraints_from_substs(def_id={:?})", def_id); + + for (i, p) in generics.type_param_defs.iter().enumerate() { + let variance_decl = + self.declared_variance(p.def_id, def_id, TypeParam, i); + let variance_i = self.xform(variance, variance_decl); + self.add_constraints_from_ty(substs.tps[i], variance_i); + } + + match substs.regions { + ty::ErasedRegions => {} + ty::NonerasedRegions(ref rps) => { + for (i, p) in generics.region_param_defs.iter().enumerate() { + let variance_decl = + self.declared_variance(p.def_id, def_id, RegionParam, i); + let variance_i = self.xform(variance, variance_decl); + self.add_constraints_from_region(*rps.get(i), variance_i); + } + } + } + } + + fn add_constraints_from_sig(&mut self, + sig: &ty::FnSig, + variance: VarianceTermPtr<'self>) { + let contra = self.contravariant(variance); + for &input in sig.inputs.iter() { + self.add_constraints_from_ty(input, contra); + } + self.add_constraints_from_ty(sig.output, variance); + } + + fn add_constraints_from_region(&mut self, + region: ty::Region, + variance: VarianceTermPtr<'self>) { + match region { + ty::re_type_bound(param_id, _, _) => { + let index = self.inferred_index(param_id); + self.add_constraint(index, variance); + } + + ty::re_static => { } + + ty::re_fn_bound(*) => { + // We do not infer variance for region parameters on + // methods or in fn types. + } + + ty::re_free(*) | ty::re_scope(*) | ty::re_infer(*) | + ty::re_empty => { + // We don't expect to see anything but 'static or bound + // regions when visiting member types or method types. + self.tcx().sess.bug(format!("Unexpected region encountered in \ + variance inference: {}", + region.repr(self.tcx()))); + } + } + } + + fn add_constraints_from_mt(&mut self, + mt: &ty::mt, + variance: VarianceTermPtr<'self>) { + match mt.mutbl { + ast::MutMutable => { + let invar = self.invariant(variance); + self.add_constraints_from_ty(mt.ty, invar); + } + + ast::MutImmutable => { + self.add_constraints_from_ty(mt.ty, variance); + } + } + } +} + +/************************************************************************** + * Constraint solving + * + * The final phase iterates over the constraints, refining the variance + * for each inferred until a fixed point is reached. This will be the + * maximal solution to the constraints. The final variance for each + * inferred is then written into the `variance_map` in the tcx. + */ + +struct SolveContext<'self> { + terms_cx: TermsContext<'self>, + constraints: ~[Constraint<'self>], + solutions: ~[ty::Variance] +} + +fn solve_constraints(constraints_cx: ConstraintContext) { + let ConstraintContext { terms_cx, constraints, _ } = constraints_cx; + let solutions = vec::from_elem(terms_cx.num_inferred(), ty::Bivariant); + let mut solutions_cx = SolveContext { + terms_cx: terms_cx, + constraints: constraints, + solutions: solutions + }; + solutions_cx.solve(); + solutions_cx.write(); +} + +impl<'self> SolveContext<'self> { + fn solve(&mut self) { + // Propagate constraints until a fixed point is reached. Note + // that the maximum number of iterations is 2C where C is the + // number of constraints (each variable can change values at most + // twice). Since number of constraints is linear in size of the + // input, so is the inference process. + let mut changed = true; + while changed { + changed = false; + + for constraint in self.constraints.iter() { + let Constraint { inferred, variance: term } = *constraint; + let variance = self.evaluate(term); + let old_value = self.solutions[*inferred]; + let new_value = glb(variance, old_value); + if old_value != new_value { + debug!("Updating inferred {} (node {}) \ + from {:?} to {:?} due to {}", + *inferred, + self.terms_cx.inferred_infos[*inferred].param_id, + old_value, + new_value, + term.to_str()); + + self.solutions[*inferred] = new_value; + changed = true; + } + } + } + } + + fn write(&self) { + // Collect all the variances for a particular item and stick + // them into the variance map. We rely on the fact that we + // generate all the inferreds for a particular item + // consecutively. + let tcx = self.terms_cx.tcx; + let item_variance_map = tcx.item_variance_map; + let solutions = &self.solutions; + let inferred_infos = &self.terms_cx.inferred_infos; + let mut index = 0; + let num_inferred = self.terms_cx.num_inferred(); + while index < num_inferred { + let item_id = inferred_infos[index].item_id; + let mut item_variances = ty::ItemVariances { + self_param: None, + type_params: opt_vec::Empty, + region_params: opt_vec::Empty + }; + while (index < num_inferred && + inferred_infos[index].item_id == item_id) { + let info = &inferred_infos[index]; + match info.kind { + SelfParam => { + assert!(item_variances.self_param.is_none()); + item_variances.self_param = Some(solutions[index]); + } + TypeParam => { + item_variances.type_params.push(solutions[index]); + } + RegionParam => { + item_variances.region_params.push(solutions[index]); + } + } + index += 1; + } + + debug!("item_id={} item_variances={}", + item_id, + item_variances.repr(tcx)); + + let item_def_id = ast_util::local_def(item_id); + + // For unit testing: check for a special "rustc_variance" + // attribute and report an error with various results if found. + if ty::has_attr(tcx, item_def_id, "rustc_variance") { + let found = item_variances.repr(tcx); + tcx.sess.span_err(ast_map::item_span(tcx.items, item_id), found); + } + + let newly_added = item_variance_map.insert(item_def_id, + @item_variances); + assert!(newly_added); + } + } + + fn evaluate(&self, term: VarianceTermPtr<'self>) -> ty::Variance { + match *term { + ConstantTerm(v) => { + v + } + + TransformTerm(t1, t2) => { + let v1 = self.evaluate(t1); + let v2 = self.evaluate(t2); + v1.xform(v2) + } + + InferredTerm(index) => { + self.solutions[*index] + } + } + } +} + +/************************************************************************** + * Miscellany transformations on variance + */ + +trait Xform { + fn xform(self, v: Self) -> Self; +} + +impl Xform for ty::Variance { + fn xform(self, v: ty::Variance) -> ty::Variance { + // "Variance transformation", Figure 1 of The Paper + match (self, v) { + // Figure 1, column 1. + (ty::Covariant, ty::Covariant) => ty::Covariant, + (ty::Covariant, ty::Contravariant) => ty::Contravariant, + (ty::Covariant, ty::Invariant) => ty::Invariant, + (ty::Covariant, ty::Bivariant) => ty::Bivariant, + + // Figure 1, column 2. + (ty::Contravariant, ty::Covariant) => ty::Contravariant, + (ty::Contravariant, ty::Contravariant) => ty::Covariant, + (ty::Contravariant, ty::Invariant) => ty::Invariant, + (ty::Contravariant, ty::Bivariant) => ty::Bivariant, + + // Figure 1, column 3. + (ty::Invariant, _) => ty::Invariant, + + // Figure 1, column 4. + (ty::Bivariant, _) => ty::Bivariant, + } + } +} + +fn glb(v1: ty::Variance, v2: ty::Variance) -> ty::Variance { + // Greatest lower bound of the variance lattice as + // defined in The Paper: + // + // * + // - + + // o + match (v1, v2) { + (ty::Invariant, _) | (_, ty::Invariant) => ty::Invariant, + + (ty::Covariant, ty::Contravariant) => ty::Invariant, + (ty::Contravariant, ty::Covariant) => ty::Invariant, + + (ty::Covariant, ty::Covariant) => ty::Covariant, + + (ty::Contravariant, ty::Contravariant) => ty::Contravariant, + + (x, ty::Bivariant) | (ty::Bivariant, x) => x, + } +} + diff --git a/src/test/compile-fail/regions-infer-contravariance-due-to-immutability.rs b/src/test/compile-fail/regions-infer-contravariance-due-to-immutability.rs deleted file mode 100644 index 83e39ebd9f4d0..0000000000000 --- a/src/test/compile-fail/regions-infer-contravariance-due-to-immutability.rs +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright 2012 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. - -struct contravariant<'self> { - f: &'self int -} - -fn to_same_lifetime<'r>(bi: contravariant<'r>) { - let bj: contravariant<'r> = bi; -} - -fn to_shorter_lifetime<'r>(bi: contravariant<'r>) { - let bj: contravariant<'blk> = bi; -} - -fn to_longer_lifetime<'r>(bi: contravariant<'r>) -> contravariant<'static> { - bi //~ ERROR mismatched types -} - -fn main() { -} diff --git a/src/test/compile-fail/regions-infer-contravariance-due-to-ret.rs b/src/test/compile-fail/regions-infer-contravariance-due-to-ret.rs deleted file mode 100644 index 3fcc5184b4a7c..0000000000000 --- a/src/test/compile-fail/regions-infer-contravariance-due-to-ret.rs +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright 2012 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. - -// Contravariant with respect to a region: -// -// You can upcast to a *smaller region* but not a larger one. This is -// the normal case. - -struct contravariant<'self> { - f: &'static fn() -> &'self int -} - -fn to_same_lifetime<'r>(bi: contravariant<'r>) { - let bj: contravariant<'r> = bi; -} - -fn to_shorter_lifetime<'r>(bi: contravariant<'r>) { - let bj: contravariant<'blk> = bi; -} - -fn to_longer_lifetime<'r>(bi: contravariant<'r>) -> contravariant<'static> { - bi //~ ERROR mismatched types -} - -fn main() { -} diff --git a/src/test/compile-fail/regions-infer-covariance-due-to-arg.rs b/src/test/compile-fail/regions-infer-covariance-due-to-arg.rs deleted file mode 100644 index 4b26e6b602163..0000000000000 --- a/src/test/compile-fail/regions-infer-covariance-due-to-arg.rs +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright 2012 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. - -// Covariant with respect to a region: -// -// You can upcast to a *larger region* but not a smaller one. - -struct covariant<'self> { - f: &'static fn(x: &'self int) -> int -} - -fn to_same_lifetime<'r>(bi: covariant<'r>) { - let bj: covariant<'r> = bi; -} - -fn to_shorter_lifetime<'r>(bi: covariant<'r>) { - let bj: covariant<'blk> = bi; //~ ERROR mismatched types - //~^ ERROR cannot infer an appropriate lifetime -} - -fn to_longer_lifetime<'r>(bi: covariant<'r>) -> covariant<'static> { - bi -} - -fn main() { -} diff --git a/src/test/compile-fail/regions-infer-invariance-due-to-arg-and-ret.rs b/src/test/compile-fail/regions-infer-invariance-due-to-arg-and-ret.rs deleted file mode 100644 index 0d4d4056a4401..0000000000000 --- a/src/test/compile-fail/regions-infer-invariance-due-to-arg-and-ret.rs +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright 2012 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. - -// Invariance with respect to a region: -// -// You cannot convert between regions. - -struct invariant<'self> { - f: &'self fn(x: &'self int) -> &'self int -} - -fn to_same_lifetime<'r>(bi: invariant<'r>) { - let bj: invariant<'r> = bi; -} - -fn to_shorter_lifetime<'r>(bi: invariant<'r>) { - let bj: invariant<'blk> = bi; //~ ERROR mismatched types -} - -fn to_longer_lifetime<'r>(bi: invariant<'r>) -> invariant<'static> { - bi //~ ERROR mismatched types -} - -fn main() { -} diff --git a/src/test/compile-fail/regions-infer-invariance-due-to-mutability-1.rs b/src/test/compile-fail/regions-infer-invariance-due-to-mutability-1.rs deleted file mode 100644 index f7c9e5bda3b4f..0000000000000 --- a/src/test/compile-fail/regions-infer-invariance-due-to-mutability-1.rs +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright 2012 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. - -#[feature(managed_boxes)]; - -struct invariant<'self> { - f: @mut &'self int -} - -fn to_same_lifetime<'r>(bi: invariant<'r>) { - let bj: invariant<'r> = bi; -} - -fn to_longer_lifetime<'r>(bi: invariant<'r>) -> invariant<'static> { - bi //~ ERROR mismatched types -} - -fn main() { -} diff --git a/src/test/compile-fail/regions-infer-invariance-due-to-mutability-2.rs b/src/test/compile-fail/regions-infer-invariance-due-to-mutability-2.rs deleted file mode 100644 index 522e5675bfe69..0000000000000 --- a/src/test/compile-fail/regions-infer-invariance-due-to-mutability-2.rs +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright 2012 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. - -#[feature(managed_boxes)]; - -struct invariant<'self> { - f: @mut [&'self int] -} - -fn to_same_lifetime<'r>(bi: invariant<'r>) { - let bj: invariant<'r> = bi; -} - -fn to_longer_lifetime<'r>(bi: invariant<'r>) -> invariant<'static> { - bi //~ ERROR mismatched types -} - -fn main() { -} diff --git a/src/test/compile-fail/regions-infer-invariance-due-to-mutability.rs b/src/test/compile-fail/regions-infer-invariance-due-to-mutability.rs deleted file mode 100644 index 9853741d77a11..0000000000000 --- a/src/test/compile-fail/regions-infer-invariance-due-to-mutability.rs +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright 2012 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. - -#[feature(managed_boxes)]; - -struct invariant<'self> { - f: @mut &'self int -} - -fn to_same_lifetime<'r>(bi: invariant<'r>) { - let bj: invariant<'r> = bi; -} - -fn to_shorter_lifetime<'r>(bi: invariant<'r>) { - let bj: invariant<'blk> = bi; //~ ERROR mismatched types -} - -fn to_longer_lifetime<'r>(bi: invariant<'r>) -> invariant<'static> { - bi //~ ERROR mismatched types -} - -fn main() { -} diff --git a/src/test/compile-fail/regions-variance-covariant-use-contravariant.rs b/src/test/compile-fail/regions-variance-covariant-use-contravariant.rs new file mode 100644 index 0000000000000..b004bc471a56d --- /dev/null +++ b/src/test/compile-fail/regions-variance-covariant-use-contravariant.rs @@ -0,0 +1,38 @@ +// Copyright 2012 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. + +// Test that a type which is contravariant with respect to its region +// parameter yields an error when used in a covariant way. +// +// Note: see variance-regions-*.rs for the tests that check that the +// variance inference works in the first place. + +// This is covariant with respect to 'a, meaning that +// Covariant<'foo> <: Covariant<'static> because +// 'foo <= 'static +struct Covariant<'a> { + f: extern "Rust" fn(&'a int) +} + +fn use_<'a>(c: Covariant<'a>) { + let x = 3; + + // 'b winds up being inferred to 'a because + // Covariant<'a> <: Covariant<'b> => 'a <= 'b + // + // Borrow checker then reports an error because `x` does not + // have the lifetime 'a. + collapse(&x, c); //~ ERROR borrowed value does not live long enough + + + fn collapse<'b>(x: &'b int, c: Covariant<'b>) { } +} + +fn main() {} diff --git a/src/test/compile-fail/regions-variance-invariant-use-contravariant.rs b/src/test/compile-fail/regions-variance-invariant-use-contravariant.rs new file mode 100644 index 0000000000000..b105fc72692d2 --- /dev/null +++ b/src/test/compile-fail/regions-variance-invariant-use-contravariant.rs @@ -0,0 +1,33 @@ +// Copyright 2012 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. + +// Test that a covariant region parameter used in a covariant position +// yields an error. +// +// Note: see variance-regions-*.rs for the tests that check that the +// variance inference works in the first place. + +struct Invariant<'a> { + f: &'static mut &'a int +} + +fn use_<'a>(c: Invariant<'a>) { + let x = 3; + + // 'b winds up being inferred to 'a, because that is the + // only way that Invariant<'a> <: Invariant<'b>, and hence + // we get an error in the borrow checker because &x cannot + // live that long + collapse(&x, c); //~ ERROR borrowed value does not live long enough + + fn collapse<'b>(x: &'b int, c: Invariant<'b>) { } +} + +fn main() { } diff --git a/src/test/compile-fail/regions-variance-invariant-use-covariant.rs b/src/test/compile-fail/regions-variance-invariant-use-covariant.rs new file mode 100644 index 0000000000000..9aae0f87f5bec --- /dev/null +++ b/src/test/compile-fail/regions-variance-invariant-use-covariant.rs @@ -0,0 +1,27 @@ +// Copyright 2012 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. + +// Test that a type which is invariant with respect to its region +// parameter used in a covariant way yields an error. +// +// Note: see variance-regions-*.rs for the tests that check that the +// variance inference works in the first place. + +struct Invariant<'a> { + f: &'static mut &'a int +} + +fn use_<'a>(c: Invariant<'a>) { + // For this assignment to be legal, Invariant<'a> <: Invariant<'static>, + // which (if Invariant were covariant) would require 'a <= 'static. + let _: Invariant<'static> = c; //~ ERROR mismatched types +} + +fn main() { } diff --git a/src/test/compile-fail/variance-regions-direct.rs b/src/test/compile-fail/variance-regions-direct.rs new file mode 100644 index 0000000000000..ae8444f015e7e --- /dev/null +++ b/src/test/compile-fail/variance-regions-direct.rs @@ -0,0 +1,73 @@ +// Copyright 2012 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. + +// Test that we correctly infer variance for region parameters in +// various self-contained types. + +// Regions that just appear in normal spots are contravariant: + +#[rustc_variance] +struct Test2<'a, 'b, 'c> { //~ ERROR region_params=[-, -, -] + x: &'a int, + y: &'b [int], + c: &'c str +} + +// Those same annotations in function arguments become covariant: + +#[rustc_variance] +struct Test3<'a, 'b, 'c> { //~ ERROR region_params=[+, +, +] + x: extern "Rust" fn(&'a int), + y: extern "Rust" fn(&'b [int]), + c: extern "Rust" fn(&'c str), +} + +// Mutability induces invariance: + +#[rustc_variance] +struct Test4<'a, 'b> { //~ ERROR region_params=[-, o] + x: &'a mut &'b int, +} + +// Mutability induces invariance, even when in a +// contravariant context: + +#[rustc_variance] +struct Test5<'a, 'b> { //~ ERROR region_params=[+, o] + x: extern "Rust" fn(&'a mut &'b int), +} + +// Invariance is a trap from which NO ONE CAN ESCAPE. +// In other words, even though the `&'b int` occurs in +// a argument list (which is contravariant), that +// argument list occurs in an invariant context. + +#[rustc_variance] +struct Test6<'a, 'b> { //~ ERROR region_params=[-, o] + x: &'a mut extern "Rust" fn(&'b int), +} + +// No uses at all is bivariant: + +#[rustc_variance] +struct Test7<'a> { //~ ERROR region_params=[*] + x: int +} + +// Try enums too. + +#[rustc_variance] +enum Test8<'a, 'b, 'c> { //~ ERROR region_params=[+, -, o] + Test8A(extern "Rust" fn(&'a int)), + Test8B(&'b [int]), + Test8C(&'b mut &'c str), +} + +fn main() {} diff --git a/src/test/compile-fail/variance-regions-indirect.rs b/src/test/compile-fail/variance-regions-indirect.rs new file mode 100644 index 0000000000000..fa22bb41aa321 --- /dev/null +++ b/src/test/compile-fail/variance-regions-indirect.rs @@ -0,0 +1,42 @@ +// Copyright 2012 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. + +// Test that we correctly infer variance for region parameters in +// case that involve multiple intracrate types. +// Try enums too. + +#[rustc_variance] +enum Base<'a, 'b, 'c, 'd> { //~ ERROR region_params=[+, -, o, *] + Test8A(extern "Rust" fn(&'a int)), + Test8B(&'b [int]), + Test8C(&'b mut &'c str), +} + +#[rustc_variance] +struct Derived1<'w, 'x, 'y, 'z> { //~ ERROR region_params=[*, o, -, +] + f: Base<'z, 'y, 'x, 'w> +} + +#[rustc_variance] // Combine - and + to yield o +struct Derived2<'a, 'b, 'c> { //~ ERROR region_params=[o, o, *] + f: Base<'a, 'a, 'b, 'c> +} + +#[rustc_variance] // Combine + and o to yield o (just pay attention to 'a here) +struct Derived3<'a, 'b, 'c> { //~ ERROR region_params=[o, -, *] + f: Base<'a, 'b, 'a, 'c> +} + +#[rustc_variance] // Combine + and * to yield + (just pay attention to 'a here) +struct Derived4<'a, 'b, 'c> { //~ ERROR region_params=[+, -, o] + f: Base<'a, 'b, 'c, 'a> +} + +fn main() {} diff --git a/src/test/run-pass/regions-variance-contravariant-use-contravariant.rs b/src/test/run-pass/regions-variance-contravariant-use-contravariant.rs new file mode 100644 index 0000000000000..1cc9a501ab6f4 --- /dev/null +++ b/src/test/run-pass/regions-variance-contravariant-use-contravariant.rs @@ -0,0 +1,32 @@ +// Copyright 2012 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. + +// Test that a type which is contravariant with respect to its region +// parameter compiles successfully when used in a contravariant way. +// +// Note: see compile-fail/variance-regions-*.rs for the tests that check that the +// variance inference works in the first place. + +struct Contravariant<'a> { + f: &'a int +} + +fn use_<'a>(c: Contravariant<'a>) { + let x = 3; + + // 'b winds up being inferred to this call. + // Contravariant<'a> <: Contravariant<'call> is true + // if 'call <= 'a, which is true, so no error. + collapse(&x, c); + + fn collapse<'b>(x: &'b int, c: Contravariant<'b>) { } +} + +fn main() {} diff --git a/src/test/run-pass/regions-variance-covariant-use-covariant.rs b/src/test/run-pass/regions-variance-covariant-use-covariant.rs new file mode 100644 index 0000000000000..ca32f7a52581a --- /dev/null +++ b/src/test/run-pass/regions-variance-covariant-use-covariant.rs @@ -0,0 +1,29 @@ +// Copyright 2012 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. + +// Test that a type which is covariant with respect to its region +// parameter is successful when used in a covariant way. +// +// Note: see compile-fail/variance-regions-*.rs for the tests that +// check that the variance inference works in the first place. + +// This is covariant with respect to 'a, meaning that +// Covariant<'foo> <: Covariant<'static> because +// 'foo <= 'static +struct Covariant<'a> { + f: extern "Rust" fn(&'a int) +} + +fn use_<'a>(c: Covariant<'a>) { + // OK Because Covariant<'a> <: Covariant<'static> iff 'a <= 'static + let _: Covariant<'static> = c; +} + +fn main() {} From 168ac5290e9d4a787e020735f96fa789060a8f76 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 29 Oct 2013 06:11:22 -0400 Subject: [PATCH 05/16] Move comparing of impl methods against trait from collect to check. This code fits better in check because it is checking that the impl matches the interface. This allows us to avoid the awkward constructions that lazilly collect traits and so forth. It also permits us to make use of the results of variance inference. --- src/librustc/middle/typeck/check/mod.rs | 323 +++++++++++++++++- src/librustc/middle/typeck/coherence.rs | 34 -- src/librustc/middle/typeck/collect.rs | 286 ---------------- src/test/compile-fail/class-method-missing.rs | 2 +- src/test/compile-fail/issue-3344.rs | 2 +- .../compile-fail/missing-derivable-attr.rs | 2 +- 6 files changed, 325 insertions(+), 324 deletions(-) diff --git a/src/librustc/middle/typeck/check/mod.rs b/src/librustc/middle/typeck/check/mod.rs index 982bc49341767..cf362384f3ade 100644 --- a/src/librustc/middle/typeck/check/mod.rs +++ b/src/librustc/middle/typeck/check/mod.rs @@ -603,7 +603,23 @@ pub fn check_item(ccx: @mut CrateCtxt, it: @ast::item) { for m in ms.iter() { check_method_body(ccx, &impl_tpt.generics, None, *m); } - vtable::resolve_impl(ccx, it); + + match *opt_trait_ref { + Some(ref ast_trait_ref) => { + let impl_trait_ref = + ty::node_id_to_trait_ref(ccx.tcx, ast_trait_ref.ref_id); + check_impl_methods_against_trait(ccx, + it.span, + &impl_tpt.generics, + ast_trait_ref, + impl_trait_ref, + *ms); + vtable::resolve_impl(ccx, it, &impl_tpt.generics, + impl_trait_ref); + } + None => { } + } + } ast::item_trait(_, _, ref trait_methods) => { let trait_def = ty::lookup_trait_def(ccx.tcx, local_def(it.id)); @@ -707,6 +723,311 @@ fn check_method_body(ccx: @mut CrateCtxt, param_env); } +fn check_impl_methods_against_trait(ccx: @mut CrateCtxt, + impl_span: Span, + impl_generics: &ty::Generics, + ast_trait_ref: &ast::trait_ref, + impl_trait_ref: &ty::TraitRef, + impl_methods: &[@ast::method]) { + // Locate trait methods + let tcx = ccx.tcx; + let trait_methods = ty::trait_methods(tcx, impl_trait_ref.def_id); + + // Check existing impl methods to see if they are both present in trait + // and compatible with trait signature + for impl_method in impl_methods.iter() { + let impl_method_def_id = local_def(impl_method.id); + let impl_method_ty = ty::method(ccx.tcx, impl_method_def_id); + + // If this is an impl of a trait method, find the corresponding + // method definition in the trait. + let opt_trait_method_ty = + trait_methods.iter(). + find(|tm| tm.ident.name == impl_method_ty.ident.name); + match opt_trait_method_ty { + Some(trait_method_ty) => { + compare_impl_method(ccx.tcx, + impl_generics, + impl_method_ty, + impl_method.span, + impl_method.body.id, + *trait_method_ty, + &impl_trait_ref.substs); + } + None => { + tcx.sess.span_err( + impl_method.span, + format!("method `{}` is not a member of trait `{}`", + tcx.sess.str_of(impl_method_ty.ident), + pprust::path_to_str(&ast_trait_ref.path, + tcx.sess.intr()))); + } + } + } + + // Check for missing methods from trait + let provided_methods = ty::provided_trait_methods(tcx, + impl_trait_ref.def_id); + let mut missing_methods = ~[]; + for trait_method in trait_methods.iter() { + let is_implemented = + impl_methods.iter().any( + |m| m.ident.name == trait_method.ident.name); + let is_provided = + provided_methods.iter().any( + |m| m.ident.name == trait_method.ident.name); + if !is_implemented && !is_provided { + missing_methods.push( + format!("`{}`", ccx.tcx.sess.str_of(trait_method.ident))); + } + } + + if !missing_methods.is_empty() { + tcx.sess.span_err( + impl_span, + format!("not all trait methods implemented, missing: {}", + missing_methods.connect(", "))); + } +} + +/** + * Checks that a method from an impl/class conforms to the signature of + * the same method as declared in the trait. + * + * # Parameters + * + * - impl_generics: the generics declared on the impl itself (not the method!) + * - impl_m: type of the method we are checking + * - impl_m_span: span to use for reporting errors + * - impl_m_body_id: id of the method body + * - trait_m: the method in the trait + * - trait_substs: the substitutions used on the type of the trait + * - self_ty: the self type of the impl + */ +pub fn compare_impl_method(tcx: ty::ctxt, + impl_generics: &ty::Generics, + impl_m: @ty::Method, + impl_m_span: Span, + impl_m_body_id: ast::NodeId, + trait_m: &ty::Method, + trait_substs: &ty::substs) { + debug!("compare_impl_method()"); + let infcx = infer::new_infer_ctxt(tcx); + + let impl_tps = impl_generics.type_param_defs.len(); + + // Try to give more informative error messages about self typing + // mismatches. Note that any mismatch will also be detected + // below, where we construct a canonical function type that + // includes the self parameter as a normal parameter. It's just + // that the error messages you get out of this code are a bit more + // inscrutable, particularly for cases where one method has no + // self. + match (&trait_m.explicit_self, &impl_m.explicit_self) { + (&ast::sty_static, &ast::sty_static) => {} + (&ast::sty_static, _) => { + tcx.sess.span_err( + impl_m_span, + format!("method `{}` has a `{}` declaration in the impl, \ + but not in the trait", + tcx.sess.str_of(trait_m.ident), + pprust::explicit_self_to_str(&impl_m.explicit_self, + tcx.sess.intr()))); + return; + } + (_, &ast::sty_static) => { + tcx.sess.span_err( + impl_m_span, + format!("method `{}` has a `{}` declaration in the trait, \ + but not in the impl", + tcx.sess.str_of(trait_m.ident), + pprust::explicit_self_to_str(&trait_m.explicit_self, + tcx.sess.intr()))); + return; + } + _ => { + // Let the type checker catch other errors below + } + } + + let num_impl_m_type_params = impl_m.generics.type_param_defs.len(); + let num_trait_m_type_params = trait_m.generics.type_param_defs.len(); + if num_impl_m_type_params != num_trait_m_type_params { + tcx.sess.span_err( + impl_m_span, + format!("method `{}` has {} type parameter(s), but its trait \ + declaration has {} type parameter(s)", + tcx.sess.str_of(trait_m.ident), + num_impl_m_type_params, + num_trait_m_type_params)); + return; + } + + if impl_m.fty.sig.inputs.len() != trait_m.fty.sig.inputs.len() { + tcx.sess.span_err( + impl_m_span, + format!("method `{}` has {} parameter(s) \ + but the trait has {} parameter(s)", + tcx.sess.str_of(trait_m.ident), + impl_m.fty.sig.inputs.len(), + trait_m.fty.sig.inputs.len())); + return; + } + + for (i, trait_param_def) in trait_m.generics.type_param_defs.iter().enumerate() { + // For each of the corresponding impl ty param's bounds... + let impl_param_def = &impl_m.generics.type_param_defs[i]; + + // Check that the impl does not require any builtin-bounds + // that the trait does not guarantee: + let extra_bounds = + impl_param_def.bounds.builtin_bounds - + trait_param_def.bounds.builtin_bounds; + if !extra_bounds.is_empty() { + tcx.sess.span_err( + impl_m_span, + format!("in method `{}`, \ + type parameter {} requires `{}`, \ + which is not required by \ + the corresponding type parameter \ + in the trait declaration", + tcx.sess.str_of(trait_m.ident), + i, + extra_bounds.user_string(tcx))); + return; + } + + // FIXME(#2687)---we should be checking that the bounds of the + // trait imply the bounds of the subtype, but it appears we + // are...not checking this. + if impl_param_def.bounds.trait_bounds.len() != + trait_param_def.bounds.trait_bounds.len() + { + tcx.sess.span_err( + impl_m_span, + format!("in method `{}`, \ + type parameter {} has {} trait bound(s), but the \ + corresponding type parameter in \ + the trait declaration has {} trait bound(s)", + tcx.sess.str_of(trait_m.ident), + i, impl_param_def.bounds.trait_bounds.len(), + trait_param_def.bounds.trait_bounds.len())); + return; + } + } + + // Create a substitution that maps the type parameters on the impl + // to themselves and which replace any references to bound regions + // in the self type with free regions. So, for example, if the + // impl type is "&'self str", then this would replace the self + // type with a free region `self`. + let dummy_impl_tps: ~[ty::t] = + impl_generics.type_param_defs.iter().enumerate(). + map(|(i,t)| ty::mk_param(tcx, i, t.def_id)). + collect(); + let dummy_method_tps: ~[ty::t] = + impl_m.generics.type_param_defs.iter().enumerate(). + map(|(i,t)| ty::mk_param(tcx, i + impl_tps, t.def_id)). + collect(); + let dummy_impl_regions: OptVec = + impl_generics.region_param_defs.iter(). + map(|l| ty::re_free(ty::FreeRegion { + scope_id: impl_m_body_id, + bound_region: ty::br_named(l.def_id, l.ident)})). + collect(); + let dummy_substs = ty::substs { + tps: vec::append(dummy_impl_tps, dummy_method_tps), + regions: ty::NonerasedRegions(dummy_impl_regions), + self_ty: None }; + + // We are going to create a synthetic fn type that includes + // both the method's self argument and its normal arguments. + // So a method like `fn(&self, a: uint)` would be converted + // into a function `fn(self: &T, a: uint)`. + let mut trait_fn_args = ~[]; + let mut impl_fn_args = ~[]; + + // For both the trait and the impl, create an argument to + // represent the self argument (unless this is a static method). + // This argument will have the *transformed* self type. + for &t in trait_m.transformed_self_ty.iter() { + trait_fn_args.push(t); + } + for &t in impl_m.transformed_self_ty.iter() { + impl_fn_args.push(t); + } + + // Add in the normal arguments. + trait_fn_args.push_all(trait_m.fty.sig.inputs); + impl_fn_args.push_all(impl_m.fty.sig.inputs); + + // Create a bare fn type for trait/impl that includes self argument + let trait_fty = + ty::mk_bare_fn(tcx, + ty::BareFnTy { + purity: trait_m.fty.purity, + abis: trait_m.fty.abis, + sig: ty::FnSig { + binder_id: trait_m.fty.sig.binder_id, + inputs: trait_fn_args, + output: trait_m.fty.sig.output, + variadic: false + } + }); + let impl_fty = + ty::mk_bare_fn(tcx, + ty::BareFnTy { + purity: impl_m.fty.purity, + abis: impl_m.fty.abis, + sig: ty::FnSig { + binder_id: impl_m.fty.sig.binder_id, + inputs: impl_fn_args, + output: impl_m.fty.sig.output, + variadic: false + } + }); + + // Perform substitutions so that the trait/impl methods are expressed + // in terms of the same set of type/region parameters: + // - replace trait type parameters with those from `trait_substs`, + // except with any reference to bound self replaced with `dummy_self_r` + // - replace method parameters on the trait with fresh, dummy parameters + // that correspond to the parameters we will find on the impl + // - replace self region with a fresh, dummy region + let impl_fty = { + debug!("impl_fty (pre-subst): {}", ppaux::ty_to_str(tcx, impl_fty)); + impl_fty.subst(tcx, &dummy_substs) + }; + debug!("impl_fty (post-subst): {}", ppaux::ty_to_str(tcx, impl_fty)); + let trait_fty = { + let substs { regions: trait_regions, + tps: trait_tps, + self_ty: self_ty } = trait_substs.subst(tcx, &dummy_substs); + let substs = substs { + regions: trait_regions, + tps: vec::append(trait_tps, dummy_method_tps), + self_ty: self_ty, + }; + debug!("trait_fty (pre-subst): {} substs={}", + trait_fty.repr(tcx), substs.repr(tcx)); + trait_fty.subst(tcx, &substs) + }; + debug!("trait_fty (post-subst): {}", trait_fty.repr(tcx)); + + match infer::mk_subty(infcx, false, infer::MethodCompatCheck(impl_m_span), + impl_fty, trait_fty) { + result::Ok(()) => {} + result::Err(ref terr) => { + tcx.sess.span_err( + impl_m_span, + format!("method `{}` has an incompatible type: {}", + tcx.sess.str_of(trait_m.ident), + ty::type_err_to_str(tcx, terr))); + ty::note_and_explain_type_err(tcx, terr); + } + } +} + impl AstConv for FnCtxt { fn tcx(&self) -> ty::ctxt { self.ccx.tcx } diff --git a/src/librustc/middle/typeck/coherence.rs b/src/librustc/middle/typeck/coherence.rs index b959c80db38a8..bf00bee270943 100644 --- a/src/librustc/middle/typeck/coherence.rs +++ b/src/librustc/middle/typeck/coherence.rs @@ -536,33 +536,6 @@ impl CoherenceChecker { return trait_id; } - // This check doesn't really have anything to do with coherence. It's - // here for historical reasons - pub fn check_trait_methods_are_implemented( - &self, - all_methods: &mut ~[@Method], - trait_did: DefId, - trait_ref_span: Span) { - - let tcx = self.crate_context.tcx; - - let mut provided_names = HashSet::new(); - // Implemented methods - for elt in all_methods.iter() { - provided_names.insert(elt.ident.name); - } - - let r = ty::trait_methods(tcx, trait_did); - for method in r.iter() { - debug!("checking for {}", method.ident.repr(tcx)); - if provided_names.contains(&method.ident.name) { continue; } - - tcx.sess.span_err(trait_ref_span, - format!("missing method `{}`", - tcx.sess.str_of(method.ident))); - } - } - /// For coherence, when we have `impl Type`, we need to guarantee that /// `Type` is "local" to the crate. For our purposes, this means that it /// must precisely name some nominal type defined in this crate. @@ -617,17 +590,10 @@ impl CoherenceChecker { let ty_trait_ref = ty::node_id_to_trait_ref( self.crate_context.tcx, trait_ref.ref_id); - let trait_did = ty_trait_ref.def_id; self.instantiate_default_methods(local_def(item.id), ty_trait_ref, &mut methods); - - // Check that we have implementations of every trait method - self.check_trait_methods_are_implemented( - &mut methods, - trait_did, - trait_ref.path.span); } return @Impl { diff --git a/src/librustc/middle/typeck/collect.rs b/src/librustc/middle/typeck/collect.rs index c1908e69f1e09..7cf004be5e2a5 100644 --- a/src/librustc/middle/typeck/collect.rs +++ b/src/librustc/middle/typeck/collect.rs @@ -411,290 +411,6 @@ pub fn ensure_supertraits(ccx: &CrateCtxt, bounds } -/** - * Checks that a method from an impl/class conforms to the signature of - * the same method as declared in the trait. - * - * # Parameters - * - * - impl_tps: the type params declared on the impl itself (not the method!) - * - cm: info about the method we are checking - * - trait_m: the method in the trait - * - trait_substs: the substitutions used on the type of the trait - * - self_ty: the self type of the impl - */ -pub fn compare_impl_method(tcx: ty::ctxt, - impl_tps: uint, - cm: &ConvertedMethod, - trait_m: &ty::Method, - trait_substs: &ty::substs, - self_ty: ty::t) { - debug!("compare_impl_method()"); - let infcx = infer::new_infer_ctxt(tcx); - - let impl_m = &cm.mty; - - // Try to give more informative error messages about self typing - // mismatches. Note that any mismatch will also be detected - // below, where we construct a canonical function type that - // includes the self parameter as a normal parameter. It's just - // that the error messages you get out of this code are a bit more - // inscrutable, particularly for cases where one method has no - // self. - match (&trait_m.explicit_self, &impl_m.explicit_self) { - (&ast::sty_static, &ast::sty_static) => {} - (&ast::sty_static, _) => { - tcx.sess.span_err( - cm.span, - format!("method `{}` has a `{}` declaration in the impl, \ - but not in the trait", - tcx.sess.str_of(trait_m.ident), - explicit_self_to_str(&impl_m.explicit_self, tcx.sess.intr()))); - return; - } - (_, &ast::sty_static) => { - tcx.sess.span_err( - cm.span, - format!("method `{}` has a `{}` declaration in the trait, \ - but not in the impl", - tcx.sess.str_of(trait_m.ident), - explicit_self_to_str(&trait_m.explicit_self, tcx.sess.intr()))); - return; - } - _ => { - // Let the type checker catch other errors below - } - } - - let num_impl_m_type_params = impl_m.generics.type_param_defs.len(); - let num_trait_m_type_params = trait_m.generics.type_param_defs.len(); - if num_impl_m_type_params != num_trait_m_type_params { - tcx.sess.span_err( - cm.span, - format!("method `{}` has {} type {}, but its trait \ - declaration has {} type {}", - tcx.sess.str_of(trait_m.ident), - num_impl_m_type_params, - pluralize(num_impl_m_type_params, ~"parameter"), - num_trait_m_type_params, - pluralize(num_trait_m_type_params, ~"parameter"))); - return; - } - - if impl_m.fty.sig.inputs.len() != trait_m.fty.sig.inputs.len() { - tcx.sess.span_err( - cm.span, - format!("method `{}` has {} parameter{} \ - but the trait has {}", - tcx.sess.str_of(trait_m.ident), - impl_m.fty.sig.inputs.len(), - if impl_m.fty.sig.inputs.len() == 1 { "" } else { "s" }, - trait_m.fty.sig.inputs.len())); - return; - } - - for (i, trait_param_def) in trait_m.generics.type_param_defs.iter().enumerate() { - // For each of the corresponding impl ty param's bounds... - let impl_param_def = &impl_m.generics.type_param_defs[i]; - - // Check that the impl does not require any builtin-bounds - // that the trait does not guarantee: - let extra_bounds = - impl_param_def.bounds.builtin_bounds - - trait_param_def.bounds.builtin_bounds; - if !extra_bounds.is_empty() { - tcx.sess.span_err( - cm.span, - format!("in method `{}`, \ - type parameter {} requires `{}`, \ - which is not required by \ - the corresponding type parameter \ - in the trait declaration", - tcx.sess.str_of(trait_m.ident), - i, - extra_bounds.user_string(tcx))); - return; - } - - // FIXME(#2687)---we should be checking that the bounds of the - // trait imply the bounds of the subtype, but it appears we - // are...not checking this. - if impl_param_def.bounds.trait_bounds.len() != - trait_param_def.bounds.trait_bounds.len() - { - tcx.sess.span_err( - cm.span, - format!("in method `{}`, \ - type parameter {} has {} trait {}, but the \ - corresponding type parameter in \ - the trait declaration has {} trait {}", - tcx.sess.str_of(trait_m.ident), - i, impl_param_def.bounds.trait_bounds.len(), - pluralize(impl_param_def.bounds.trait_bounds.len(), - ~"bound"), - trait_param_def.bounds.trait_bounds.len(), - pluralize(trait_param_def.bounds.trait_bounds.len(), - ~"bound"))); - return; - } - } - - // Replace any references to the self region in the self type with - // a free region. So, for example, if the impl type is - // "&'self str", then this would replace the self type with a free - // region `self`. - let dummy_self_r = ty::re_free(ty::FreeRegion {scope_id: cm.body_id, - bound_region: ty::br_self}); - let self_ty = replace_bound_self(tcx, self_ty, dummy_self_r); - - // We are going to create a synthetic fn type that includes - // both the method's self argument and its normal arguments. - // So a method like `fn(&self, a: uint)` would be converted - // into a function `fn(self: &T, a: uint)`. - let mut trait_fn_args = ~[]; - let mut impl_fn_args = ~[]; - - // For both the trait and the impl, create an argument to - // represent the self argument (unless this is a static method). - // This argument will have the *transformed* self type. - for &t in trait_m.transformed_self_ty.iter() { - trait_fn_args.push(t); - } - for &t in impl_m.transformed_self_ty.iter() { - impl_fn_args.push(t); - } - - // Add in the normal arguments. - trait_fn_args.push_all(trait_m.fty.sig.inputs); - impl_fn_args.push_all(impl_m.fty.sig.inputs); - - // Create a bare fn type for trait/impl that includes self argument - let trait_fty = - ty::mk_bare_fn(tcx, - ty::BareFnTy { - purity: trait_m.fty.purity, - abis: trait_m.fty.abis, - sig: ty::FnSig { - bound_lifetime_names: - trait_m.fty - .sig - .bound_lifetime_names - .clone(), - inputs: trait_fn_args, - output: trait_m.fty.sig.output, - variadic: false - } - }); - let impl_fty = - ty::mk_bare_fn(tcx, - ty::BareFnTy { - purity: impl_m.fty.purity, - abis: impl_m.fty.abis, - sig: ty::FnSig { - bound_lifetime_names: - impl_m.fty - .sig - .bound_lifetime_names - .clone(), - inputs: impl_fn_args, - output: impl_m.fty.sig.output, - variadic: false - } - }); - - // Perform substitutions so that the trait/impl methods are expressed - // in terms of the same set of type/region parameters: - // - replace trait type parameters with those from `trait_substs`, - // except with any reference to bound self replaced with `dummy_self_r` - // - replace method parameters on the trait with fresh, dummy parameters - // that correspond to the parameters we will find on the impl - // - replace self region with a fresh, dummy region - let impl_fty = { - debug!("impl_fty (pre-subst): {}", ppaux::ty_to_str(tcx, impl_fty)); - replace_bound_self(tcx, impl_fty, dummy_self_r) - }; - debug!("impl_fty (post-subst): {}", ppaux::ty_to_str(tcx, impl_fty)); - let trait_fty = { - let num_trait_m_type_params = trait_m.generics.type_param_defs.len(); - let dummy_tps = do vec::from_fn(num_trait_m_type_params) |i| { - ty::mk_param(tcx, i + impl_tps, - impl_m.generics.type_param_defs[i].def_id) - }; - let trait_tps = trait_substs.tps.map( - |t| replace_bound_self(tcx, *t, dummy_self_r)); - let substs = substs { - regions: ty::NonerasedRegions(opt_vec::with(dummy_self_r)), - self_ty: Some(self_ty), - tps: vec::append(trait_tps, dummy_tps) - }; - debug!("trait_fty (pre-subst): {} substs={}", - trait_fty.repr(tcx), substs.repr(tcx)); - ty::subst(tcx, &substs, trait_fty) - }; - debug!("trait_fty (post-subst): {}", trait_fty.repr(tcx)); - - match infer::mk_subty(infcx, false, infer::MethodCompatCheck(cm.span), - impl_fty, trait_fty) { - result::Ok(()) => {} - result::Err(ref terr) => { - tcx.sess.span_err( - cm.span, - format!("method `{}` has an incompatible type: {}", - tcx.sess.str_of(trait_m.ident), - ty::type_err_to_str(tcx, terr))); - ty::note_and_explain_type_err(tcx, terr); - } - } - return; - - // Replaces bound references to the self region with `with_r`. - fn replace_bound_self(tcx: ty::ctxt, ty: ty::t, - with_r: ty::Region) -> ty::t { - do ty::fold_regions(tcx, ty) |r, _in_fn| { - if r == ty::re_bound(ty::br_self) {with_r} else {r} - } - } -} - -pub fn check_methods_against_trait(ccx: &CrateCtxt, - generics: &ast::Generics, - rp: Option, - selfty: ty::t, - a_trait_ty: &ast::trait_ref, - impl_ms: &[ConvertedMethod]) -{ - let tcx = ccx.tcx; - let trait_ref = instantiate_trait_ref(ccx, a_trait_ty, rp, - generics, selfty); - - if trait_ref.def_id.crate == ast::LOCAL_CRATE { - ensure_trait_methods(ccx, trait_ref.def_id.node); - } - - // Check that each method we impl is a method on the trait - // Trait methods we don't implement must be default methods, but if not - // we'll catch it in coherence - let trait_ms = ty::trait_methods(tcx, trait_ref.def_id); - for impl_m in impl_ms.iter() { - match trait_ms.iter().find(|trait_m| trait_m.ident.name == impl_m.mty.ident.name) { - Some(trait_m) => { - let num_impl_tps = generics.ty_params.len(); - compare_impl_method( - ccx.tcx, num_impl_tps, impl_m, *trait_m, - &trait_ref.substs, selfty); - } - None => { - // This method is not part of the trait - tcx.sess.span_err( - impl_m.span, - format!("method `{}` is not a member of trait `{}`", - tcx.sess.str_of(impl_m.mty.ident), - path_to_str(&a_trait_ty.path, tcx.sess.intr()))); - } - } - } -} // fn - pub fn convert_field(ccx: &CrateCtxt, struct_generics: &ty::Generics, v: &ast::struct_field) { @@ -849,8 +565,6 @@ pub fn convert(ccx: &CrateCtxt, it: &ast::item) { "cannot provide an explicit implementation \ for a builtin kind"); } - - check_methods_against_trait(ccx, generics, rp, selfty, t, cms); } } ast::item_trait(ref generics, _, ref trait_methods) => { diff --git a/src/test/compile-fail/class-method-missing.rs b/src/test/compile-fail/class-method-missing.rs index f3c5ab2019dae..ca97a8997689f 100644 --- a/src/test/compile-fail/class-method-missing.rs +++ b/src/test/compile-fail/class-method-missing.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// error-pattern:missing method `eat` trait animal { fn eat(&self); } @@ -18,6 +17,7 @@ struct cat { } impl animal for cat { + //~^ ERROR not all trait methods implemented, missing: `eat` } fn cat(in_x : uint) -> cat { diff --git a/src/test/compile-fail/issue-3344.rs b/src/test/compile-fail/issue-3344.rs index 9a3fff453f3a0..1a649c8ad2f83 100644 --- a/src/test/compile-fail/issue-3344.rs +++ b/src/test/compile-fail/issue-3344.rs @@ -9,7 +9,7 @@ // except according to those terms. struct thing(uint); -impl Ord for thing { //~ ERROR missing method `lt` +impl Ord for thing { //~ ERROR not all trait methods implemented, missing: `lt` fn le(&self, other: &thing) -> bool { **self < **other } fn ge(&self, other: &thing) -> bool { **self < **other } } diff --git a/src/test/compile-fail/missing-derivable-attr.rs b/src/test/compile-fail/missing-derivable-attr.rs index 70c16e0baefb8..4e45f33fe9b14 100644 --- a/src/test/compile-fail/missing-derivable-attr.rs +++ b/src/test/compile-fail/missing-derivable-attr.rs @@ -20,7 +20,7 @@ impl MyEq for int { fn eq(&self, other: &int) -> bool { *self == *other } } -impl MyEq for A {} //~ ERROR missing method +impl MyEq for A {} //~ ERROR not all trait methods implemented, missing: `eq` fn main() { } From f57a28b2dbb1823b88b5db270145a4f324820390 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 29 Oct 2013 06:12:50 -0400 Subject: [PATCH 06/16] Improve error reporting for region inference failures to make use of all the information it has at its disposal. Unfortunately this also reveals that we need to improve the reporting heuristics further, as sometimes the errors it chooses to emit seem somewhat mystifying and are not related to the actual problem. --- .../middle/typeck/infer/error_reporting.rs | 194 ++++++++++++++++-- 1 file changed, 174 insertions(+), 20 deletions(-) diff --git a/src/librustc/middle/typeck/infer/error_reporting.rs b/src/librustc/middle/typeck/infer/error_reporting.rs index 3f38850c8ffda..635de28194df9 100644 --- a/src/librustc/middle/typeck/infer/error_reporting.rs +++ b/src/librustc/middle/typeck/infer/error_reporting.rs @@ -73,6 +73,7 @@ use middle::typeck::infer::region_inference::SubSupConflict; use middle::typeck::infer::region_inference::SupSupConflict; use syntax::opt_vec::OptVec; use util::ppaux::UserString; +use util::ppaux::bound_region_to_str; use util::ppaux::note_and_explain_region; pub trait ErrorReporting { @@ -110,6 +111,13 @@ pub trait ErrorReporting { region2: Region); } +trait ErrorReportingHelpers { + fn report_inference_failure(@mut self, + var_origin: RegionVariableOrigin); + + fn note_region_origin(@mut self, + origin: SubregionOrigin); +} impl ErrorReporting for InferCtxt { fn report_region_errors(@mut self, @@ -398,10 +406,7 @@ impl ErrorReporting for InferCtxt { sub_region: Region, sup_origin: SubregionOrigin, sup_region: Region) { - self.tcx.sess.span_err( - var_origin.span(), - format!("cannot infer an appropriate lifetime \ - due to conflicting requirements")); + self.report_inference_failure(var_origin); note_and_explain_region( self.tcx, @@ -409,9 +414,7 @@ impl ErrorReporting for InferCtxt { sup_region, "..."); - self.tcx.sess.span_note( - sup_origin.span(), - format!("...due to the following expression")); + self.note_region_origin(sup_origin); note_and_explain_region( self.tcx, @@ -419,9 +422,7 @@ impl ErrorReporting for InferCtxt { sub_region, "..."); - self.tcx.sess.span_note( - sub_origin.span(), - format!("...due to the following expression")); + self.note_region_origin(sub_origin); } fn report_sup_sup_conflict(@mut self, @@ -430,10 +431,7 @@ impl ErrorReporting for InferCtxt { region1: Region, origin2: SubregionOrigin, region2: Region) { - self.tcx.sess.span_err( - var_origin.span(), - format!("cannot infer an appropriate lifetime \ - due to conflicting requirements")); + self.report_inference_failure(var_origin); note_and_explain_region( self.tcx, @@ -441,9 +439,7 @@ impl ErrorReporting for InferCtxt { region1, "..."); - self.tcx.sess.span_note( - origin1.span(), - format!("...due to the following expression")); + self.note_region_origin(origin1); note_and_explain_region( self.tcx, @@ -451,9 +447,167 @@ impl ErrorReporting for InferCtxt { region2, "..."); - self.tcx.sess.span_note( - origin2.span(), - format!("...due to the following expression")); + self.note_region_origin(origin2); + } +} + +impl ErrorReportingHelpers for InferCtxt { + fn report_inference_failure(@mut self, + var_origin: RegionVariableOrigin) { + let var_description = match var_origin { + infer::MiscVariable(_) => ~"", + infer::PatternRegion(_) => ~" for pattern", + infer::AddrOfRegion(_) => ~" for borrow expression", + infer::AddrOfSlice(_) => ~" for slice expression", + infer::Autoref(_) => ~" for autoref", + infer::Coercion(_) => ~" for automatic coercion", + infer::BoundRegionInFnCall(_, br) => { + format!(" for {}in function call", + bound_region_to_str(self.tcx, "region ", true, br)) + } + infer::BoundRegionInFnType(_, br) => { + format!(" for {}in function type", + bound_region_to_str(self.tcx, "region ", true, br)) + } + infer::BoundRegionInTypeOrImpl(_) => { + format!(" for region in type/impl") + } + infer::BoundRegionInCoherence(*) => { + format!(" for coherence check") + } + }; + + self.tcx.sess.span_err( + var_origin.span(), + format!("cannot infer an appropriate lifetime{} \ + due to conflicting requirements", + var_description)); + } + + fn note_region_origin(@mut self, + origin: SubregionOrigin) { + match origin { + infer::Subtype(ref trace) => { + let desc = match trace.origin { + infer::Misc(_) => { + format!("types are compatible") + } + infer::MethodCompatCheck(_) => { + format!("method type is compatible with trait") + } + infer::ExprAssignable(_) => { + format!("expression is assignable") + } + infer::RelateTraitRefs(_) => { + format!("traits are compatible") + } + infer::RelateSelfType(_) => { + format!("type matches impl") + } + infer::MatchExpression(_) => { + format!("match arms have compatible types") + } + infer::IfExpression(_) => { + format!("if and else have compatible types") + } + }; + + match self.values_str(&trace.values) { + Some(values_str) => { + self.tcx.sess.span_note( + trace.origin.span(), + format!("...so that {} ({})", + desc, values_str)); + } + None => { + // Really should avoid printing this error at + // all, since it is derived, but that would + // require more refactoring than I feel like + // doing right now. - nmatsakis + self.tcx.sess.span_note( + trace.origin.span(), + format!("...so that {}", desc)); + } + } + } + infer::Reborrow(span) => { + self.tcx.sess.span_note( + span, + "...so that borrowed pointer does not outlive \ + borrowed content"); + } + infer::InfStackClosure(span) => { + self.tcx.sess.span_note( + span, + "...so that closure does not outlive its stack frame"); + } + infer::InvokeClosure(span) => { + self.tcx.sess.span_note( + span, + "...so that closure is not invoked outside its lifetime"); + } + infer::DerefPointer(span) => { + self.tcx.sess.span_note( + span, + "...so that pointer is not dereferenced \ + outside its lifetime"); + } + infer::FreeVariable(span) => { + self.tcx.sess.span_note( + span, + "...so that captured variable does not outlive the \ + enclosing closure"); + } + infer::IndexSlice(span) => { + self.tcx.sess.span_note( + span, + "...so that slice is not indexed outside the lifetime"); + } + infer::RelateObjectBound(span) => { + self.tcx.sess.span_note( + span, + "...so that source pointer does not outlive \ + lifetime bound of the object type"); + } + infer::CallRcvr(span) => { + self.tcx.sess.span_note( + span, + "...so that method receiver is valid for the method call"); + } + infer::CallArg(span) => { + self.tcx.sess.span_note( + span, + "...so that argument is valid for the call"); + } + infer::CallReturn(span) => { + self.tcx.sess.span_note( + span, + "...so that return value is valid for the call"); + } + infer::AddrOf(span) => { + self.tcx.sess.span_note( + span, + "...so that borrowed pointer is valid \ + at the time of borrow"); + } + infer::AutoBorrow(span) => { + self.tcx.sess.span_note( + span, + "...so that automatically borrowed pointer is valid \ + at the time of borrow"); + } + infer::BindingTypeIsNotValidAtDecl(span) => { + self.tcx.sess.span_note( + span, + "...so that variable is valid at time of its declaration"); + } + infer::ReferenceOutlivesReferent(_, span) => { + self.tcx.sess.span_note( + span, + "...so that the pointer does not outlive the \ + data it points at"); + } + } } } From 5e54a7323dc3cc8b121de313b9af2d16424b086e Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 29 Oct 2013 06:14:59 -0400 Subject: [PATCH 07/16] Update various tests and libraries that were incorrectly annotated. --- Makefile.in | 1 + src/libextra/arc.rs | 28 +++++++++---------- src/librustc/driver/driver.rs | 5 +--- src/librustc/metadata/tydecode.rs | 22 +++++++-------- src/librustc/middle/trans/type_of.rs | 19 +++++++++++-- .../compile-fail/bad-mid-path-type-params.rs | 7 +++-- .../compile-fail/core-tls-store-pointer.rs | 2 +- src/test/compile-fail/issue-4335.rs | 2 +- src/test/compile-fail/issue-5216.rs | 8 +++--- .../kindck-owned-trait-contains.rs | 25 +++++++---------- src/test/compile-fail/regions-addr-of-arg.rs | 9 +++++- src/test/compile-fail/regions-addr-of-self.rs | 4 +-- .../regions-addr-of-upvar-self.rs | 2 +- src/test/compile-fail/regions-fn-subtyping.rs | 8 +++--- .../regions-free-region-ordering-callee.rs | 2 +- .../regions-free-region-ordering-caller.rs | 6 ---- .../regions-free-region-ordering-caller1.rs | 24 ++++++++++++++++ src/test/compile-fail/regions-in-consts.rs | 3 +- ...type-items.rs => regions-in-enums-anon.rs} | 12 ++------ src/test/compile-fail/regions-in-enums.rs | 14 +++++++--- ...ions-blk.rs => regions-in-structs-anon.rs} | 16 +++-------- src/test/compile-fail/regions-in-structs.rs | 14 ++++++---- ...regions-infer-region-in-fn-but-not-type.rs | 2 +- .../compile-fail/regions-ret-borrowed-1.rs | 2 +- src/test/compile-fail/regions-undeclared.rs | 23 +++++++++++++++ .../trait-impl-different-num-params.rs | 2 +- ...ddr-of.rs => regions-dependent-addr-of.rs} | 0 ...-autofn.rs => regions-dependent-autofn.rs} | 0 ...lice.rs => regions-dependent-autoslice.rs} | 0 src/test/run-pass/regions-mock-trans.rs | 2 +- ...s => regions-return-interior-of-option.rs} | 0 31 files changed, 156 insertions(+), 108 deletions(-) create mode 100644 src/test/compile-fail/regions-free-region-ordering-caller1.rs rename src/test/compile-fail/{regions-in-type-items.rs => regions-in-enums-anon.rs} (73%) rename src/test/compile-fail/{regions-blk.rs => regions-in-structs-anon.rs} (62%) create mode 100644 src/test/compile-fail/regions-undeclared.rs rename src/test/run-pass/{region-dependent-addr-of.rs => regions-dependent-addr-of.rs} (100%) rename src/test/run-pass/{region-dependent-autofn.rs => regions-dependent-autofn.rs} (100%) rename src/test/run-pass/{region-dependent-autoslice.rs => regions-dependent-autoslice.rs} (100%) rename src/test/run-pass/{region-return-interior-of-option.rs => regions-return-interior-of-option.rs} (100%) diff --git a/Makefile.in b/Makefile.in index b927c805220f4..f5bb3cb2ed00f 100644 --- a/Makefile.in +++ b/Makefile.in @@ -125,6 +125,7 @@ ifdef TRACE CFG_RUSTC_FLAGS += -Z trace endif ifndef DEBUG_BORROWS + RUSTFLAGS_STAGE0 += -Z no-debug-borrows RUSTFLAGS_STAGE1 += -Z no-debug-borrows RUSTFLAGS_STAGE2 += -Z no-debug-borrows endif diff --git a/src/libextra/arc.rs b/src/libextra/arc.rs index df67b1c9cc1df..b3da9b4f16b88 100644 --- a/src/libextra/arc.rs +++ b/src/libextra/arc.rs @@ -233,10 +233,10 @@ impl MutexArc { /// As unsafe_access(), but with a condvar, as sync::mutex.lock_cond(). #[inline] - pub unsafe fn unsafe_access_cond<'x, 'c, U>(&self, - blk: &fn(x: &'x mut T, - c: &'c Condvar) -> U) - -> U { + pub unsafe fn unsafe_access_cond(&self, + blk: &fn(x: &mut T, + c: &Condvar) -> U) + -> U { let state = self.x.get(); do (&(*state).lock).lock_cond |cond| { check_poison(true, (*state).failed); @@ -290,10 +290,10 @@ impl MutexArc { /// As unsafe_access_cond but safe and Freeze. #[inline] - pub fn access_cond<'x, 'c, U>(&self, - blk: &fn(x: &'x mut T, - c: &'c Condvar) -> U) - -> U { + pub fn access_cond(&self, + blk: &fn(x: &mut T, + c: &Condvar) -> U) + -> U { unsafe { self.unsafe_access_cond(blk) } } } @@ -402,9 +402,9 @@ impl RWArc { /// As write(), but with a condvar, as sync::rwlock.write_cond(). #[inline] - pub fn write_cond<'x, 'c, U>(&self, - blk: &fn(x: &'x mut T, c: &'c Condvar) -> U) - -> U { + pub fn write_cond(&self, + blk: &fn(x: &mut T, c: &Condvar) -> U) + -> U { unsafe { let state = self.x.get(); do (*borrow_rwlock(state)).write_cond |cond| { @@ -554,9 +554,9 @@ impl<'self, T:Freeze + Send> RWWriteMode<'self, T> { } /// Access the pre-downgrade RWArc in write mode with a condvar. - pub fn write_cond<'x, 'c, U>(&mut self, - blk: &fn(x: &'x mut T, c: &'c Condvar) -> U) - -> U { + pub fn write_cond(&mut self, + blk: &fn(x: &mut T, c: &Condvar) -> U) + -> U { match *self { RWWriteMode { data: &ref mut data, diff --git a/src/librustc/driver/driver.rs b/src/librustc/driver/driver.rs index 380991266822c..6346e4856f2d1 100644 --- a/src/librustc/driver/driver.rs +++ b/src/librustc/driver/driver.rs @@ -249,10 +249,7 @@ pub fn phase_3_run_analysis_passes(sess: Session, freevars::annotate_freevars(def_map, crate)); let region_map = time(time_passes, "region resolution", (), |_| - middle::region::resolve_crate(sess, def_map, crate)); - - let rp_set = time(time_passes, "region parameterization inference", (), |_| - middle::region::determine_rp_in_crate(sess, ast_map, def_map, crate)); + middle::region::resolve_crate(sess, crate)); let ty_cx = ty::mk_ctxt(sess, def_map, named_region_map, ast_map, freevars, region_map, lang_items); diff --git a/src/librustc/metadata/tydecode.rs b/src/librustc/metadata/tydecode.rs index 1636205c76d62..6e06cef55ee22 100644 --- a/src/librustc/metadata/tydecode.rs +++ b/src/librustc/metadata/tydecode.rs @@ -363,18 +363,18 @@ fn parse_ty(st: &mut PState, conv: conv_did) -> ty::t { return ty::mk_param(st.tcx, parse_uint(st), did); } 's' => { - let did = parse_def(st, TypeParameter, conv); + let did = parse_def(st, TypeParameter, |x,y| conv(x,y)); return ty::mk_self(st.tcx, did); } - '@' => return ty::mk_box(st.tcx, parse_mt(st, conv)), - '~' => return ty::mk_uniq(st.tcx, parse_mt(st, conv)), - '*' => return ty::mk_ptr(st.tcx, parse_mt(st, conv)), + '@' => return ty::mk_box(st.tcx, parse_mt(st, |x,y| conv(x,y))), + '~' => return ty::mk_uniq(st.tcx, parse_mt(st, |x,y| conv(x,y))), + '*' => return ty::mk_ptr(st.tcx, parse_mt(st, |x,y| conv(x,y))), '&' => { - let r = parse_region(st); - let mt = parse_mt(st, conv); + let r = parse_region(st, |x,y| conv(x,y)); + let mt = parse_mt(st, |x,y| conv(x,y)); return ty::mk_rptr(st.tcx, r, mt); } - 'U' => return ty::mk_unboxed_vec(st.tcx, parse_mt(st, conv)), + 'U' => return ty::mk_unboxed_vec(st.tcx, parse_mt(st, |x,y| conv(x,y))), 'V' => { let mt = parse_mt(st, |x,y| conv(x,y)); let v = parse_vstore(st, |x,y| conv(x,y)); @@ -392,10 +392,10 @@ fn parse_ty(st: &mut PState, conv: conv_did) -> ty::t { return ty::mk_tup(st.tcx, params); } 'f' => { - return ty::mk_closure(st.tcx, parse_closure_ty(st, conv)); + return ty::mk_closure(st.tcx, parse_closure_ty(st, |x,y| conv(x,y))); } 'F' => { - return ty::mk_bare_fn(st.tcx, parse_bare_fn_ty(st, conv)); + return ty::mk_bare_fn(st.tcx, parse_bare_fn_ty(st, |x,y| conv(x,y))); } 'Y' => return ty::mk_type(st.tcx), 'C' => { @@ -417,7 +417,7 @@ fn parse_ty(st: &mut PState, conv: conv_did) -> ty::t { pos: pos, .. *st }; - let tt = parse_ty(&mut ps, conv); + let tt = parse_ty(&mut ps, |x,y| conv(x,y)); st.tcx.rcache.insert(key, tt); return tt; } @@ -449,7 +449,7 @@ fn parse_mutability(st: &mut PState) -> ast::Mutability { fn parse_mt(st: &mut PState, conv: conv_did) -> ty::mt { let m = parse_mutability(st); - ty::mt { ty: parse_ty(st, conv), mutbl: m } + ty::mt { ty: parse_ty(st, |x,y| conv(x,y)), mutbl: m } } fn parse_def(st: &mut PState, source: DefIdSource, diff --git a/src/librustc/middle/trans/type_of.rs b/src/librustc/middle/trans/type_of.rs index 604321a0492a1..36af13d34e656 100644 --- a/src/librustc/middle/trans/type_of.rs +++ b/src/librustc/middle/trans/type_of.rs @@ -14,6 +14,7 @@ use middle::trans::common::*; use middle::trans::foreign; use middle::ty; use util::ppaux; +use util::ppaux::Repr; use middle::trans::type_::Type; @@ -172,14 +173,16 @@ pub fn sizing_type_of(cx: &mut CrateContext, t: ty::t) -> Type { // NB: If you update this, be sure to update `sizing_type_of()` as well. pub fn type_of(cx: &mut CrateContext, t: ty::t) -> Type { - debug!("type_of {:?}: {:?}", t, ty::get(t)); - // Check the cache. match cx.lltypes.find(&t) { - Some(&t) => return t, + Some(&llty) => { + return llty; + } None => () } + debug!("type_of {} {:?}", t.repr(cx.tcx), t); + // Replace any typedef'd types with their equivalent non-typedef // type. This ensures that all LLVM nominal types that contain // Rust types are defined as the same LLVM types. If we don't do @@ -189,6 +192,12 @@ pub fn type_of(cx: &mut CrateContext, t: ty::t) -> Type { if t != t_norm { let llty = type_of(cx, t_norm); + debug!("--> normalized {} {:?} to {} {:?} llty={}", + t.repr(cx.tcx), + t, + t_norm.repr(cx.tcx), + t_norm, + cx.tn.type_to_str(llty)); cx.lltypes.insert(t, llty); return llty; } @@ -299,6 +308,10 @@ pub fn type_of(cx: &mut CrateContext, t: ty::t) -> Type { ty::ty_err(*) => cx.tcx.sess.bug("type_of with ty_err") }; + debug!("--> mapped t={} {:?} to llty={}", + t.repr(cx.tcx), + t, + cx.tn.type_to_str(llty)); cx.lltypes.insert(t, llty); // If this was an enum or struct, fill in the type now. diff --git a/src/test/compile-fail/bad-mid-path-type-params.rs b/src/test/compile-fail/bad-mid-path-type-params.rs index f9f4ccf0f0751..90d6147f0eda3 100644 --- a/src/test/compile-fail/bad-mid-path-type-params.rs +++ b/src/test/compile-fail/bad-mid-path-type-params.rs @@ -28,10 +28,11 @@ impl Trait for S2 { } } -fn main() { +fn foo<'a>() { let _ = S::new::(1, 1.0); //~ ERROR the impl referenced by this path has 1 type parameter, but 0 type parameters were supplied - let _ = S::<'self,int>::new::(1, 1.0); //~ ERROR this impl has no lifetime parameter + let _ = S::<'a,int>::new::(1, 1.0); //~ ERROR expected 0 lifetime parameter(s) let _: S2 = Trait::new::(1, 1.0); //~ ERROR the trait referenced by this path has 1 type parameter, but 0 type parameters were supplied - let _: S2 = Trait::<'self,int>::new::(1, 1.0); //~ ERROR this trait has no lifetime parameter + let _: S2 = Trait::<'a,int>::new::(1, 1.0); //~ ERROR expected 0 lifetime parameter(s) } +fn main() {} diff --git a/src/test/compile-fail/core-tls-store-pointer.rs b/src/test/compile-fail/core-tls-store-pointer.rs index 4f60391892da3..70573ca4f180c 100644 --- a/src/test/compile-fail/core-tls-store-pointer.rs +++ b/src/test/compile-fail/core-tls-store-pointer.rs @@ -13,6 +13,6 @@ use std::local_data; local_data_key!(key: @&int) -//~^ ERROR only 'static is allowed +//~^ ERROR missing lifetime specifier fn main() {} diff --git a/src/test/compile-fail/issue-4335.rs b/src/test/compile-fail/issue-4335.rs index 5b6240d8ac83b..032b2564f4fb2 100644 --- a/src/test/compile-fail/issue-4335.rs +++ b/src/test/compile-fail/issue-4335.rs @@ -10,7 +10,7 @@ fn id(t: T) -> T { t } -fn f<'r, T>(v: &'r T) -> &'r fn()->T { id::<&'r fn()->T>(|| *v) } //~ ERROR cannot infer an appropriate lifetime due to conflicting requirements +fn f<'r, T>(v: &'r T) -> &'r fn()->T { id::<&'r fn()->T>(|| *v) } //~ ERROR cannot infer an appropriate lifetime fn main() { let v = &5; diff --git a/src/test/compile-fail/issue-5216.rs b/src/test/compile-fail/issue-5216.rs index 9f88ba72f059a..8205a6dae6470 100644 --- a/src/test/compile-fail/issue-5216.rs +++ b/src/test/compile-fail/issue-5216.rs @@ -9,12 +9,12 @@ // except according to those terms. fn f() { } -struct S(&fn()); //~ ERROR Illegal anonymous lifetime -pub static C: S = S(f); //~ ERROR Illegal anonymous lifetime +struct S(&fn()); //~ ERROR missing lifetime specifier +pub static C: S = S(f); fn g() { } -type T = &fn(); //~ ERROR Illegal anonymous lifetime -pub static D: T = g; //~ ERROR Illegal anonymous lifetime +type T = &fn(); //~ ERROR missing lifetime specifier +pub static D: T = g; fn main() {} diff --git a/src/test/compile-fail/kindck-owned-trait-contains.rs b/src/test/compile-fail/kindck-owned-trait-contains.rs index fb85edf699a9b..5fe9b13f83bef 100644 --- a/src/test/compile-fail/kindck-owned-trait-contains.rs +++ b/src/test/compile-fail/kindck-owned-trait-contains.rs @@ -8,29 +8,24 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#[feature(managed_boxes)]; +trait Repeat { fn get(&self) -> A; } -trait repeat { fn get(&self) -> A; } - -impl repeat for @A { - fn get(&self) -> A { **self } +impl Repeat for A { + fn get(&self) -> A { self.clone() } } -fn repeater(v: @A) -> @repeat { - // Note: owned kind is not necessary as A appears in the trait type - @v as @repeat // No +fn repeater(v: A) -> ~Repeat: { + ~v as ~Repeat: // No } fn main() { // Error results because the type of is inferred to be - // @repeat<&'blk int> where blk is the lifetime of the block below. + // ~Repeat<&'blk int> where blk is the lifetime of the block below. - let y = { //~ ERROR lifetime of variable does not enclose its declaration - let x: &'blk int = &3; - repeater(@x) + let y = { + let tmp0 = 3; + let tmp1 = &tmp0; //~ ERROR borrowed value does not live long enough + repeater(tmp1) }; assert!(3 == *(y.get())); - //~^ ERROR dereference of reference outside its lifetime - //~^^ ERROR automatically borrowed pointer is not valid at the time of borrow - //~^^^ ERROR lifetime of return value does not outlive the function call } diff --git a/src/test/compile-fail/regions-addr-of-arg.rs b/src/test/compile-fail/regions-addr-of-arg.rs index 4fff5a6f87c78..ff13548b4946f 100644 --- a/src/test/compile-fail/regions-addr-of-arg.rs +++ b/src/test/compile-fail/regions-addr-of-arg.rs @@ -8,12 +8,19 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// Check that taking the address of an argument yields a lifetime +// bounded by the current function call. + fn foo(a: int) { let _p: &'static int = &a; //~ ERROR borrowed value does not live long enough } fn bar(a: int) { - let _q: &'blk int = &a; + let _q: &int = &a; +} + +fn zed<'a>(a: int) -> &'a int { + &a //~ ERROR borrowed value does not live long enough } fn main() { diff --git a/src/test/compile-fail/regions-addr-of-self.rs b/src/test/compile-fail/regions-addr-of-self.rs index 3a480a7e9631c..b7be0dd7b9b1e 100644 --- a/src/test/compile-fail/regions-addr-of-self.rs +++ b/src/test/compile-fail/regions-addr-of-self.rs @@ -14,12 +14,12 @@ struct dog { impl dog { pub fn chase_cat(&mut self) { - let p: &'static mut uint = &mut self.cats_chased; //~ ERROR cannot infer an appropriate lifetime due to conflicting requirements + let p: &'static mut uint = &mut self.cats_chased; //~ ERROR cannot infer an appropriate lifetime *p += 1u; } pub fn chase_cat_2(&mut self) { - let p: &'blk mut uint = &mut self.cats_chased; + let p: &mut uint = &mut self.cats_chased; *p += 1u; } } diff --git a/src/test/compile-fail/regions-addr-of-upvar-self.rs b/src/test/compile-fail/regions-addr-of-upvar-self.rs index 9cedf86f35056..2f60898cfeef1 100644 --- a/src/test/compile-fail/regions-addr-of-upvar-self.rs +++ b/src/test/compile-fail/regions-addr-of-upvar-self.rs @@ -17,7 +17,7 @@ struct dog { impl dog { pub fn chase_cat(&mut self) { let _f = || { - let p: &'static mut uint = &mut self.food; //~ ERROR cannot infer an appropriate lifetime due to conflicting requirements + let p: &'static mut uint = &mut self.food; //~ ERROR cannot infer an appropriate lifetime *p = 3u; }; } diff --git a/src/test/compile-fail/regions-fn-subtyping.rs b/src/test/compile-fail/regions-fn-subtyping.rs index 5928d31a66860..cad73daa46b15 100644 --- a/src/test/compile-fail/regions-fn-subtyping.rs +++ b/src/test/compile-fail/regions-fn-subtyping.rs @@ -24,9 +24,9 @@ fn test_fn<'x,'y,'z,T>(_x: &'x T, _y: &'y T, _z: &'z T) { of::<&fn<'b>(&'b T)>()); subtype::<&fn<'b>(&'b T)>( - of::<&fn<'x>(&'x T)>()); + of::<&fn(&'x T)>()); - subtype::<&fn<'x>(&'x T)>( + subtype::<&fn(&'x T)>( of::<&fn<'b>(&'b T)>()); //~ ERROR mismatched types subtype::<&fn<'a,'b>(&'a T, &'b T)>( @@ -36,9 +36,9 @@ fn test_fn<'x,'y,'z,T>(_x: &'x T, _y: &'y T, _z: &'z T) { of::<&fn<'a,'b>(&'a T, &'b T)>()); //~ ERROR mismatched types subtype::<&fn<'a,'b>(&'a T, &'b T)>( - of::<&fn<'x,'y>(&'x T, &'y T)>()); + of::<&fn(&'x T, &'y T)>()); - subtype::<&fn<'x,'y>(&'x T, &'y T)>( + subtype::<&fn(&'x T, &'y T)>( of::<&fn<'a,'b>(&'a T, &'b T)>()); //~ ERROR mismatched types } diff --git a/src/test/compile-fail/regions-free-region-ordering-callee.rs b/src/test/compile-fail/regions-free-region-ordering-callee.rs index 66ab4b7705433..fb31e477ba279 100644 --- a/src/test/compile-fail/regions-free-region-ordering-callee.rs +++ b/src/test/compile-fail/regions-free-region-ordering-callee.rs @@ -26,7 +26,7 @@ fn ordering2<'a, 'b>(x: &'a &'b uint, y: &'a uint) -> &'b uint { fn ordering3<'a, 'b>(x: &'a uint, y: &'b uint) -> &'a &'b uint { // Do not infer an ordering from the return value. let z: &'b uint = &*x; - //~^ ERROR cannot infer an appropriate lifetime due to conflicting requirements + //~^ ERROR cannot infer an appropriate lifetime fail!(); } diff --git a/src/test/compile-fail/regions-free-region-ordering-caller.rs b/src/test/compile-fail/regions-free-region-ordering-caller.rs index c9859899ea4f1..58fa437a6a365 100644 --- a/src/test/compile-fail/regions-free-region-ordering-caller.rs +++ b/src/test/compile-fail/regions-free-region-ordering-caller.rs @@ -14,12 +14,6 @@ struct Paramd<'self> { x: &'self uint } -fn call1<'a>(x: &'a uint) { - let y: uint = 3; - let z: &'a &'blk uint = &(&y); - //~^ ERROR pointer has a longer lifetime than the data it references -} - fn call2<'a, 'b>(a: &'a uint, b: &'b uint) { let z: Option<&'b &'a uint> = None; //~^ ERROR pointer has a longer lifetime than the data it references diff --git a/src/test/compile-fail/regions-free-region-ordering-caller1.rs b/src/test/compile-fail/regions-free-region-ordering-caller1.rs new file mode 100644 index 0000000000000..1408f75be896e --- /dev/null +++ b/src/test/compile-fail/regions-free-region-ordering-caller1.rs @@ -0,0 +1,24 @@ +// Copyright 2012 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. + +// Test various ways to construct a pointer with a longer lifetime +// than the thing it points at and ensure that they result in +// errors. See also regions-free-region-ordering-callee.rs + +fn call1<'a>(x: &'a uint) { + // Test that creating a pointer like + // &'a &'z uint requires that 'a <= 'z: + let y: uint = 3; + let z: &'a & uint = &(&y); + //~^ ERROR borrowed value does not live long enough + //~^^ ERROR borrowed value does not live long enough +} + +fn main() {} diff --git a/src/test/compile-fail/regions-in-consts.rs b/src/test/compile-fail/regions-in-consts.rs index c34e5fb29de5a..9f2facf4e1f9f 100644 --- a/src/test/compile-fail/regions-in-consts.rs +++ b/src/test/compile-fail/regions-in-consts.rs @@ -8,8 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -static c_x: &'blk int = &22; //~ ERROR Illegal lifetime 'blk: only 'static is allowed here -static c_y: &int = &22; //~ ERROR Illegal anonymous lifetime: only 'static is allowed here +static c_y: &int = &22; //~ ERROR missing lifetime specifier static c_z: &'static int = &22; fn main() { diff --git a/src/test/compile-fail/regions-in-type-items.rs b/src/test/compile-fail/regions-in-enums-anon.rs similarity index 73% rename from src/test/compile-fail/regions-in-type-items.rs rename to src/test/compile-fail/regions-in-enums-anon.rs index a30a6772bfd21..5c7a37d0359a4 100644 --- a/src/test/compile-fail/regions-in-type-items.rs +++ b/src/test/compile-fail/regions-in-enums-anon.rs @@ -8,16 +8,10 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -struct item_ty_yes0<'self> { - x: &'self uint -} - -struct item_ty_yes1<'self> { - x: &'self uint -} +// Test that anonymous lifetimes are not permitted in enum declarations -struct item_ty_yes2 { - x: &'a uint //~ ERROR only 'self is allowed +enum Foo { + Bar(&int) //~ ERROR missing lifetime specifier } fn main() {} diff --git a/src/test/compile-fail/regions-in-enums.rs b/src/test/compile-fail/regions-in-enums.rs index f189deef32e5d..0a221b9a53390 100644 --- a/src/test/compile-fail/regions-in-enums.rs +++ b/src/test/compile-fail/regions-in-enums.rs @@ -8,17 +8,23 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// Test that lifetimes must be declared for use on enums. +// See also regions-undeclared.rs + enum yes0<'lt> { - // This will eventually be legal (and in fact the only way): - X3(&'lt uint) //~ ERROR Illegal lifetime 'lt: only 'self is allowed + X3(&'lt uint) } enum yes1<'self> { X4(&'self uint) } -enum yes2 { - X5(&'foo uint) //~ ERROR Illegal lifetime 'foo: only 'self is allowed +enum no0 { + X5(&'foo uint) //~ ERROR use of undeclared lifetime name `'foo` +} + +enum no1 { + X6(&'self uint) //~ ERROR use of undeclared lifetime name `'self` } fn main() {} diff --git a/src/test/compile-fail/regions-blk.rs b/src/test/compile-fail/regions-in-structs-anon.rs similarity index 62% rename from src/test/compile-fail/regions-blk.rs rename to src/test/compile-fail/regions-in-structs-anon.rs index 893e4c411780b..0f2036a56cdd6 100644 --- a/src/test/compile-fail/regions-blk.rs +++ b/src/test/compile-fail/regions-in-structs-anon.rs @@ -8,18 +8,10 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -fn foo(cond: bool) { - let x = 5; - let mut y: &'blk int = &x; +// Test that anonymous lifetimes are not permitted in struct declarations - let mut z: &'blk int; - if cond { - z = &x; //~ ERROR cannot infer an appropriate lifetime due to conflicting requirements - } else { - let w: &'blk int = &x; - z = w; - } +struct Foo { + x: &int //~ ERROR missing lifetime specifier } -fn main() { -} +fn main() {} diff --git a/src/test/compile-fail/regions-in-structs.rs b/src/test/compile-fail/regions-in-structs.rs index c4f1a8ae465ec..1e74fa4adb9f6 100644 --- a/src/test/compile-fail/regions-in-structs.rs +++ b/src/test/compile-fail/regions-in-structs.rs @@ -8,16 +8,18 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -struct yes0<'self> { - x: &uint, //~ ERROR Illegal anonymous lifetime: anonymous lifetimes are not permitted here -} - struct yes1<'self> { x: &'self uint, } -struct yes2<'self> { - x: &'foo uint, //~ ERROR Illegal lifetime 'foo: only 'self is allowed +struct yes2<'a> { + x: &'a uint, } +struct StructDecl { + a: &'a int, //~ ERROR use of undeclared lifetime name `'a` + b: &'self int, //~ ERROR use of undeclared lifetime name `'self` +} + + fn main() {} diff --git a/src/test/compile-fail/regions-infer-region-in-fn-but-not-type.rs b/src/test/compile-fail/regions-infer-region-in-fn-but-not-type.rs index 4c3338d2e1d0c..5c979955ec9ae 100644 --- a/src/test/compile-fail/regions-infer-region-in-fn-but-not-type.rs +++ b/src/test/compile-fail/regions-infer-region-in-fn-but-not-type.rs @@ -13,7 +13,7 @@ // contains region pointers struct foo(~fn(x: &int)); -fn take_foo(x: foo<'static>) {} //~ ERROR no region bound is allowed on `foo` +fn take_foo(x: foo<'static>) {} //~ ERROR wrong number of lifetime parameters fn main() { } diff --git a/src/test/compile-fail/regions-ret-borrowed-1.rs b/src/test/compile-fail/regions-ret-borrowed-1.rs index df7831e905056..ee6ed3b0d76f6 100644 --- a/src/test/compile-fail/regions-ret-borrowed-1.rs +++ b/src/test/compile-fail/regions-ret-borrowed-1.rs @@ -12,7 +12,7 @@ // some point regions-ret-borrowed reported an error but this file did // not, due to special hardcoding around the anonymous region. -fn with<'a, R>(f: &fn(x: &'a int) -> R) -> R { +fn with(f: &fn<'a>(x: &'a int) -> R) -> R { f(&3) } diff --git a/src/test/compile-fail/regions-undeclared.rs b/src/test/compile-fail/regions-undeclared.rs new file mode 100644 index 0000000000000..fcf3a73b19f0d --- /dev/null +++ b/src/test/compile-fail/regions-undeclared.rs @@ -0,0 +1,23 @@ +// Copyright 2012 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. + +static c_x: &'blk int = &22; //~ ERROR use of undeclared lifetime name `'blk` + +enum EnumDecl { + Foo(&'a int), //~ ERROR use of undeclared lifetime name `'a` + Bar(&'self int), //~ ERROR use of undeclared lifetime name `'self` +} + +fn fnDecl(x: &'a int, //~ ERROR use of undeclared lifetime name `'a` + y: &'self int) //~ ERROR use of undeclared lifetime name `'self` +{} + +fn main() { +} diff --git a/src/test/compile-fail/trait-impl-different-num-params.rs b/src/test/compile-fail/trait-impl-different-num-params.rs index 7039e05019958..940c1b3a237b8 100644 --- a/src/test/compile-fail/trait-impl-different-num-params.rs +++ b/src/test/compile-fail/trait-impl-different-num-params.rs @@ -13,7 +13,7 @@ trait foo { } impl foo for int { fn bar(&self) -> int { - //~^ ERROR method `bar` has 0 parameters but the trait has 1 + //~^ ERROR method `bar` has 0 parameter(s) but the trait has 1 *self } } diff --git a/src/test/run-pass/region-dependent-addr-of.rs b/src/test/run-pass/regions-dependent-addr-of.rs similarity index 100% rename from src/test/run-pass/region-dependent-addr-of.rs rename to src/test/run-pass/regions-dependent-addr-of.rs diff --git a/src/test/run-pass/region-dependent-autofn.rs b/src/test/run-pass/regions-dependent-autofn.rs similarity index 100% rename from src/test/run-pass/region-dependent-autofn.rs rename to src/test/run-pass/regions-dependent-autofn.rs diff --git a/src/test/run-pass/region-dependent-autoslice.rs b/src/test/run-pass/regions-dependent-autoslice.rs similarity index 100% rename from src/test/run-pass/region-dependent-autoslice.rs rename to src/test/run-pass/regions-dependent-autoslice.rs diff --git a/src/test/run-pass/regions-mock-trans.rs b/src/test/run-pass/regions-mock-trans.rs index e66a34b47bce0..6740230728c6c 100644 --- a/src/test/run-pass/regions-mock-trans.rs +++ b/src/test/run-pass/regions-mock-trans.rs @@ -30,7 +30,7 @@ struct Ccx { #[fixed_stack_segment] #[inline(never)] fn alloc<'a>(_bcx : &'a arena) -> &'a Bcx<'a> { unsafe { - cast::transmute(libc::malloc(mem::size_of::>() + cast::transmute(libc::malloc(mem::size_of::>() as libc::size_t)) } } diff --git a/src/test/run-pass/region-return-interior-of-option.rs b/src/test/run-pass/regions-return-interior-of-option.rs similarity index 100% rename from src/test/run-pass/region-return-interior-of-option.rs rename to src/test/run-pass/regions-return-interior-of-option.rs From 195f1d77bd6bdd8988d5cbd107cb0c4cfa4694cc Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 29 Oct 2013 10:34:11 -0400 Subject: [PATCH 08/16] Rename and modernize region enum names --- src/librustc/metadata/tydecode.rs | 20 +-- src/librustc/metadata/tyencode.rs | 22 +-- src/librustc/middle/astencode.rs | 22 +-- .../middle/borrowck/gather_loans/lifetime.rs | 18 +-- .../middle/borrowck/gather_loans/mod.rs | 20 +-- src/librustc/middle/kind.rs | 6 +- src/librustc/middle/region.rs | 10 +- src/librustc/middle/resolve_lifetime.rs | 4 +- src/librustc/middle/subst.rs | 4 +- src/librustc/middle/trans/_match.rs | 4 +- src/librustc/middle/trans/consts.rs | 6 +- src/librustc/middle/trans/datum.rs | 2 +- src/librustc/middle/trans/expr.rs | 2 +- src/librustc/middle/trans/glue.rs | 2 +- src/librustc/middle/trans/reflect.rs | 2 +- src/librustc/middle/ty.rs | 74 ++++----- src/librustc/middle/typeck/astconv.rs | 28 ++-- src/librustc/middle/typeck/check/mod.rs | 26 ++-- src/librustc/middle/typeck/check/regionck.rs | 20 +-- .../middle/typeck/check/regionmanip.rs | 8 +- src/librustc/middle/typeck/check/vtable.rs | 2 +- src/librustc/middle/typeck/collect.rs | 6 +- src/librustc/middle/typeck/infer/glb.rs | 6 +- src/librustc/middle/typeck/infer/lattice.rs | 6 +- src/librustc/middle/typeck/infer/lub.rs | 4 +- src/librustc/middle/typeck/infer/mod.rs | 16 +- .../typeck/infer/region_inference/mod.rs | 140 +++++++++--------- src/librustc/middle/typeck/infer/resolve.rs | 6 +- src/librustc/middle/typeck/infer/sub.rs | 2 +- src/librustc/middle/typeck/infer/test.rs | 12 +- src/librustc/middle/typeck/mod.rs | 10 +- src/librustc/middle/typeck/rscope.rs | 6 +- src/librustc/middle/typeck/variance.rs | 10 +- src/librustc/util/ppaux.rs | 94 ++++++------ src/libsyntax/ast.rs | 4 +- 35 files changed, 316 insertions(+), 308 deletions(-) diff --git a/src/librustc/metadata/tydecode.rs b/src/librustc/metadata/tydecode.rs index 6e06cef55ee22..18447e6cbc8cd 100644 --- a/src/librustc/metadata/tydecode.rs +++ b/src/librustc/metadata/tydecode.rs @@ -228,22 +228,22 @@ fn parse_region_substs(st: &mut PState, conv: conv_did) -> ty::RegionSubsts { } } -fn parse_bound_region(st: &mut PState, conv: conv_did) -> ty::bound_region { +fn parse_bound_region(st: &mut PState, conv: conv_did) -> ty::BoundRegion { match next(st) { 'a' => { let id = parse_uint(st); assert_eq!(next(st), '|'); - ty::br_anon(id) + ty::BrAnon(id) } '[' => { let def = parse_def(st, RegionParameter, |x,y| conv(x,y)); let ident = st.tcx.sess.ident_of(parse_str(st, ']')); - ty::br_named(def, ident) + ty::BrNamed(def, ident) } 'f' => { let id = parse_uint(st); assert_eq!(next(st), '|'); - ty::br_fresh(id) + ty::BrFresh(id) } _ => fail!("parse_bound_region: bad input") } @@ -257,7 +257,7 @@ fn parse_region(st: &mut PState, conv: conv_did) -> ty::Region { assert_eq!(next(st), '|'); let br = parse_bound_region(st, |x,y| conv(x,y)); assert_eq!(next(st), ']'); - ty::re_fn_bound(id, br) + ty::ReLateBound(id, br) } 'B' => { assert_eq!(next(st), '['); @@ -266,7 +266,7 @@ fn parse_region(st: &mut PState, conv: conv_did) -> ty::Region { let index = parse_uint(st); assert_eq!(next(st), '|'); let nm = st.tcx.sess.ident_of(parse_str(st, ']')); - ty::re_type_bound(node_id, index, nm) + ty::ReEarlyBound(node_id, index, nm) } 'f' => { assert_eq!(next(st), '['); @@ -274,19 +274,19 @@ fn parse_region(st: &mut PState, conv: conv_did) -> ty::Region { assert_eq!(next(st), '|'); let br = parse_bound_region(st, |x,y| conv(x,y)); assert_eq!(next(st), ']'); - ty::re_free(ty::FreeRegion {scope_id: id, + ty::ReFree(ty::FreeRegion {scope_id: id, bound_region: br}) } 's' => { let id = parse_uint(st) as int; assert_eq!(next(st), '|'); - ty::re_scope(id) + ty::ReScope(id) } 't' => { - ty::re_static + ty::ReStatic } 'e' => { - ty::re_static + ty::ReStatic } _ => fail!("parse_region: bad input") } diff --git a/src/librustc/metadata/tyencode.rs b/src/librustc/metadata/tyencode.rs index af28162dbfd5d..d304db0935ac5 100644 --- a/src/librustc/metadata/tyencode.rs +++ b/src/librustc/metadata/tyencode.rs @@ -155,49 +155,49 @@ fn enc_region_substs(w: @mut MemWriter, cx: @ctxt, substs: &ty::RegionSubsts) { fn enc_region(w: @mut MemWriter, cx: @ctxt, r: ty::Region) { match r { - ty::re_fn_bound(id, br) => { + ty::ReLateBound(id, br) => { mywrite!(w, "b[{}|", id); enc_bound_region(w, cx, br); mywrite!(w, "]"); } - ty::re_type_bound(node_id, index, ident) => { + ty::ReEarlyBound(node_id, index, ident) => { mywrite!(w, "B[{}|{}|{}]", node_id, index, cx.tcx.sess.str_of(ident)); } - ty::re_free(ref fr) => { + ty::ReFree(ref fr) => { mywrite!(w, "f[{}|", fr.scope_id); enc_bound_region(w, cx, fr.bound_region); mywrite!(w, "]"); } - ty::re_scope(nid) => { + ty::ReScope(nid) => { mywrite!(w, "s{}|", nid); } - ty::re_static => { + ty::ReStatic => { mywrite!(w, "t"); } - ty::re_empty => { + ty::ReEmpty => { mywrite!(w, "e"); } - ty::re_infer(_) => { + ty::ReInfer(_) => { // these should not crop up after typeck cx.diag.handler().bug("Cannot encode region variables"); } } } -fn enc_bound_region(w: @mut MemWriter, cx: @ctxt, br: ty::bound_region) { +fn enc_bound_region(w: @mut MemWriter, cx: @ctxt, br: ty::BoundRegion) { match br { - ty::br_anon(idx) => { + ty::BrAnon(idx) => { mywrite!(w, "a{}|", idx); } - ty::br_named(d, s) => { + ty::BrNamed(d, s) => { mywrite!(w, "[{}|{}]", (cx.ds)(d), cx.tcx.sess.str_of(s)); } - ty::br_fresh(id) => { + ty::BrFresh(id) => { mywrite!(w, "f{}|", id); } } diff --git a/src/librustc/middle/astencode.rs b/src/librustc/middle/astencode.rs index e60b9382be49a..09c0951b9e3c5 100644 --- a/src/librustc/middle/astencode.rs +++ b/src/librustc/middle/astencode.rs @@ -476,27 +476,27 @@ impl tr for ty::AutoRef { impl tr for ty::Region { fn tr(&self, xcx: @ExtendedDecodeContext) -> ty::Region { match *self { - ty::re_fn_bound(id, br) => ty::re_fn_bound(xcx.tr_id(id), + ty::ReLateBound(id, br) => ty::ReLateBound(xcx.tr_id(id), br.tr(xcx)), - ty::re_type_bound(id, index, ident) => ty::re_type_bound(xcx.tr_id(id), + ty::ReEarlyBound(id, index, ident) => ty::ReEarlyBound(xcx.tr_id(id), index, ident), - ty::re_scope(id) => ty::re_scope(xcx.tr_id(id)), - ty::re_empty | ty::re_static | ty::re_infer(*) => *self, - ty::re_free(ref fr) => { - ty::re_free(ty::FreeRegion {scope_id: xcx.tr_id(fr.scope_id), + ty::ReScope(id) => ty::ReScope(xcx.tr_id(id)), + ty::ReEmpty | ty::ReStatic | ty::ReInfer(*) => *self, + ty::ReFree(ref fr) => { + ty::ReFree(ty::FreeRegion {scope_id: xcx.tr_id(fr.scope_id), bound_region: fr.bound_region.tr(xcx)}) } } } } -impl tr for ty::bound_region { - fn tr(&self, xcx: @ExtendedDecodeContext) -> ty::bound_region { +impl tr for ty::BoundRegion { + fn tr(&self, xcx: @ExtendedDecodeContext) -> ty::BoundRegion { match *self { - ty::br_anon(_) | - ty::br_fresh(_) => *self, - ty::br_named(id, ident) => ty::br_named(xcx.tr_def_id(id), + ty::BrAnon(_) | + ty::BrFresh(_) => *self, + ty::BrNamed(id, ident) => ty::BrNamed(xcx.tr_def_id(id), ident), } } diff --git a/src/librustc/middle/borrowck/gather_loans/lifetime.rs b/src/librustc/middle/borrowck/gather_loans/lifetime.rs index a0c6fdc32255f..a5f1709058c46 100644 --- a/src/librustc/middle/borrowck/gather_loans/lifetime.rs +++ b/src/librustc/middle/borrowck/gather_loans/lifetime.rs @@ -199,7 +199,7 @@ impl<'self> GuaranteeLifetimeContext<'self> { // Make sure that the loan does not exceed the maximum time // that we can root the value, dynamically. - let root_region = ty::re_scope(self.root_scope_id); + let root_region = ty::ReScope(self.root_scope_id); if !self.bccx.is_subregion_of(self.loan_region, root_region) { self.report_error( err_out_of_root_scope(root_region, self.loan_region)); @@ -208,9 +208,9 @@ impl<'self> GuaranteeLifetimeContext<'self> { // Extract the scope id that indicates how long the rooting is required let root_scope = match self.loan_region { - ty::re_scope(id) => id, + ty::ReScope(id) => id, _ => { - // the check above should fail for anything is not re_scope + // the check above should fail for anything is not ReScope self.bccx.tcx.sess.span_bug( cmt_base.span, format!("Cannot issue root for scope region: {:?}", @@ -260,12 +260,12 @@ impl<'self> GuaranteeLifetimeContext<'self> { note_and_explain_region( self.bccx.tcx, "managed value only needs to be frozen for ", - ty::re_scope(root_scope), + ty::ReScope(root_scope), "..."); note_and_explain_region( self.bccx.tcx, "...but due to Issue #6248, it will be frozen for ", - ty::re_scope(cleanup_scope), + ty::ReScope(cleanup_scope), ""); } @@ -324,13 +324,13 @@ impl<'self> GuaranteeLifetimeContext<'self> { match cmt.cat { mc::cat_rvalue(cleanup_scope_id) => { - ty::re_scope(cleanup_scope_id) + ty::ReScope(cleanup_scope_id) } mc::cat_copied_upvar(_) => { - ty::re_scope(self.item_scope_id) + ty::ReScope(self.item_scope_id) } mc::cat_static_item => { - ty::re_static + ty::ReStatic } mc::cat_local(local_id) | mc::cat_arg(local_id) | @@ -338,7 +338,7 @@ impl<'self> GuaranteeLifetimeContext<'self> { self.bccx.tcx.region_maps.encl_region(local_id) } mc::cat_deref(_, _, mc::unsafe_ptr(*)) => { - ty::re_static + ty::ReStatic } mc::cat_deref(_, _, mc::region_ptr(_, r)) => { r diff --git a/src/librustc/middle/borrowck/gather_loans/mod.rs b/src/librustc/middle/borrowck/gather_loans/mod.rs index 729da749ec691..56c3417852299 100644 --- a/src/librustc/middle/borrowck/gather_loans/mod.rs +++ b/src/librustc/middle/borrowck/gather_loans/mod.rs @@ -277,7 +277,7 @@ fn gather_loans_in_expr(this: &mut GatherLoanCtxt, // Currently these do not use adjustments, so we have to // hardcode this check here (note that the receiver DOES use // adjustments). - let scope_r = ty::re_scope(ex.id); + let scope_r = ty::ReScope(ex.id); let arg_cmt = this.bccx.cat_expr(arg); this.guarantee_valid(arg.id, arg.span, @@ -441,7 +441,7 @@ impl<'self> GatherLoanCtxt<'self> { // a loan for the empty region can never be dereferenced, so // it is always safe - if loan_region == ty::re_empty { + if loan_region == ty::ReEmpty { return; } @@ -470,10 +470,10 @@ impl<'self> GatherLoanCtxt<'self> { restrictions::SafeIf(loan_path, restrictions) => { let loan_scope = match loan_region { - ty::re_scope(id) => id, - ty::re_free(ref fr) => fr.scope_id, + ty::ReScope(id) => id, + ty::ReFree(ref fr) => fr.scope_id, - ty::re_static => { + ty::ReStatic => { // If we get here, an error must have been // reported in // `lifetime::guarantee_lifetime()`, because @@ -485,10 +485,10 @@ impl<'self> GatherLoanCtxt<'self> { return; } - ty::re_empty | - ty::re_fn_bound(*) | - ty::re_type_bound(*) | - ty::re_infer(*) => { + ty::ReEmpty | + ty::ReLateBound(*) | + ty::ReEarlyBound(*) | + ty::ReInfer(*) => { self.tcx().sess.span_bug( cmt.span, format!("Invalid borrow lifetime: {:?}", loan_region)); @@ -715,7 +715,7 @@ impl<'self> GatherLoanCtxt<'self> { let cmt_discr = match arm_match_ids { None => cmt, Some((arm_id, match_id)) => { - let arm_scope = ty::re_scope(arm_id); + let arm_scope = ty::ReScope(arm_id); if self.bccx.is_subregion_of(scope_r, arm_scope) { self.bccx.cat_discr(cmt, match_id) } else { diff --git a/src/librustc/middle/kind.rs b/src/librustc/middle/kind.rs index 99f2d7a87002f..a570160ce9572 100644 --- a/src/librustc/middle/kind.rs +++ b/src/librustc/middle/kind.rs @@ -545,7 +545,7 @@ pub fn check_cast_for_escaping_regions( // Check, based on the region associated with the trait, whether it can // possibly escape the enclosing fn item (note that all type parameters // must have been declared on the enclosing fn item). - if target_regions.iter().any(|r| is_re_scope(*r)) { + if target_regions.iter().any(|r| is_ReScope(*r)) { return; /* case (1) */ } @@ -584,9 +584,9 @@ pub fn check_cast_for_escaping_regions( } }); - fn is_re_scope(r: ty::Region) -> bool { + fn is_ReScope(r: ty::Region) -> bool { match r { - ty::re_scope(*) => true, + ty::ReScope(*) => true, _ => false } } diff --git a/src/librustc/middle/region.rs b/src/librustc/middle/region.rs index 80103aa410688..32ac6ff549213 100644 --- a/src/librustc/middle/region.rs +++ b/src/librustc/middle/region.rs @@ -137,7 +137,7 @@ impl RegionMaps { pub fn encl_region(&self, id: ast::NodeId) -> ty::Region { //! Returns the narrowest scope region that encloses `id`, if any. - ty::re_scope(self.encl_scope(id)) + ty::ReScope(self.encl_scope(id)) } pub fn scopes_intersect(&self, scope1: ast::NodeId, scope2: ast::NodeId) @@ -227,19 +227,19 @@ impl RegionMaps { sub_region == super_region || { match (sub_region, super_region) { - (_, ty::re_static) => { + (_, ty::ReStatic) => { true } - (ty::re_scope(sub_scope), ty::re_scope(super_scope)) => { + (ty::ReScope(sub_scope), ty::ReScope(super_scope)) => { self.is_subscope_of(sub_scope, super_scope) } - (ty::re_scope(sub_scope), ty::re_free(ref fr)) => { + (ty::ReScope(sub_scope), ty::ReFree(ref fr)) => { self.is_subscope_of(sub_scope, fr.scope_id) } - (ty::re_free(sub_fr), ty::re_free(super_fr)) => { + (ty::ReFree(sub_fr), ty::ReFree(super_fr)) => { self.sub_free_region(sub_fr, super_fr) } diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs index 98260be990230..b21720f2e30a0 100644 --- a/src/librustc/middle/resolve_lifetime.rs +++ b/src/librustc/middle/resolve_lifetime.rs @@ -176,7 +176,7 @@ impl LifetimeContext { ItemScope(lifetimes) => { match search_lifetimes(lifetimes, lifetime_ref) { Some((index, decl_id)) => { - let def = ast::DefTypeBoundRegion(index, decl_id); + let def = ast::DefEarlyBoundRegion(index, decl_id); self.insert_lifetime(lifetime_ref, def); return; } @@ -189,7 +189,7 @@ impl LifetimeContext { FnScope(id, lifetimes, s) => { match search_lifetimes(lifetimes, lifetime_ref) { Some((_index, decl_id)) => { - let def = ast::DefFnBoundRegion(id, depth, decl_id); + let def = ast::DefLateBoundRegion(id, depth, decl_id); self.insert_lifetime(lifetime_ref, def); return; } diff --git a/src/librustc/middle/subst.rs b/src/librustc/middle/subst.rs index 7654a46ec3639..c9abf71e2b6ec 100644 --- a/src/librustc/middle/subst.rs +++ b/src/librustc/middle/subst.rs @@ -193,9 +193,9 @@ impl Subst for ty::Region { // the specialized routine // `middle::typeck::check::regionmanip::replace_bound_regions_in_fn_sig()`. match self { - &ty::re_type_bound(_, i, _) => { + &ty::ReEarlyBound(_, i, _) => { match substs.regions { - ty::ErasedRegions => ty::re_static, + ty::ErasedRegions => ty::ReStatic, ty::NonerasedRegions(ref regions) => *regions.get(i), } } diff --git a/src/librustc/middle/trans/_match.rs b/src/librustc/middle/trans/_match.rs index 9bafea6d861be..9dddf96e34d57 100644 --- a/src/librustc/middle/trans/_match.rs +++ b/src/librustc/middle/trans/_match.rs @@ -1048,7 +1048,7 @@ fn extract_vec_elems(bcx: @mut Block, let slice_len = Sub(bcx, len, slice_len_offset); let slice_ty = ty::mk_evec(bcx.tcx(), ty::mt {ty: vt.unit_ty, mutbl: ast::MutImmutable}, - ty::vstore_slice(ty::re_static) + ty::vstore_slice(ty::ReStatic) ); let scratch = scratch_datum(bcx, slice_ty, "", false); Store(bcx, slice_begin, @@ -1697,7 +1697,7 @@ fn compile_submatch_continue(mut bcx: @mut Block, let t = node_id_type(bcx, pat_id); let Result {bcx: after_cx, val: matches} = { do with_scope_result(bcx, None, - "compare_scope") |bcx| { + "compaReScope") |bcx| { match trans_opt(bcx, opt) { single_result( Result {bcx, val}) => { diff --git a/src/librustc/middle/trans/consts.rs b/src/librustc/middle/trans/consts.rs index 9f497afb1213f..06fe4717f58e1 100644 --- a/src/librustc/middle/trans/consts.rs +++ b/src/librustc/middle/trans/consts.rs @@ -181,7 +181,7 @@ pub fn const_expr(cx: @mut CrateContext, e: &ast::Expr) -> (ValueRef, bool) { let adjustment = cx.tcx.adjustments.find_copy(&e.id); match adjustment { None => { } - Some(@ty::AutoAddEnv(ty::re_static, ast::BorrowedSigil)) => { + Some(@ty::AutoAddEnv(ty::ReStatic, ast::BorrowedSigil)) => { llconst = C_struct([llconst, C_null(Type::opaque_box(cx).ptr_to())], false) } Some(@ty::AutoAddEnv(ref r, ref s)) => { @@ -211,11 +211,11 @@ pub fn const_expr(cx: @mut CrateContext, e: &ast::Expr) -> (ValueRef, bool) { }; match *autoref { ty::AutoUnsafe(m) | - ty::AutoPtr(ty::re_static, m) => { + ty::AutoPtr(ty::ReStatic, m) => { assert!(m != ast::MutMutable); llconst = llptr; } - ty::AutoBorrowVec(ty::re_static, m) => { + ty::AutoBorrowVec(ty::ReStatic, m) => { assert!(m != ast::MutMutable); assert_eq!(abi::slice_elt_base, 0); assert_eq!(abi::slice_elt_len, 1); diff --git a/src/librustc/middle/trans/datum.rs b/src/librustc/middle/trans/datum.rs index 1efa7f763d8f9..01cf102275023 100644 --- a/src/librustc/middle/trans/datum.rs +++ b/src/librustc/middle/trans/datum.rs @@ -588,7 +588,7 @@ impl Datum { // result (which will be by-value). Note that it is not // significant *which* region we pick here. let llval = self.to_ref_llval(bcx); - let rptr_ty = ty::mk_imm_rptr(bcx.tcx(), ty::re_static, + let rptr_ty = ty::mk_imm_rptr(bcx.tcx(), ty::ReStatic, self.ty); Datum {val: llval, ty: rptr_ty, mode: ByValue} } diff --git a/src/librustc/middle/trans/expr.rs b/src/librustc/middle/trans/expr.rs index f291f088dec6c..ddf9354ad3835 100644 --- a/src/librustc/middle/trans/expr.rs +++ b/src/librustc/middle/trans/expr.rs @@ -271,7 +271,7 @@ pub fn trans_to_datum(bcx: @mut Block, expr: &ast::Expr) -> DatumBlock { // real one, but it will have the same runtime representation let slice_ty = ty::mk_evec(tcx, ty::mt { ty: unit_ty, mutbl: ast::MutImmutable }, - ty::vstore_slice(ty::re_static)); + ty::vstore_slice(ty::ReStatic)); let scratch = scratch_datum(bcx, slice_ty, "__adjust", false); diff --git a/src/librustc/middle/trans/glue.rs b/src/librustc/middle/trans/glue.rs index f461120e4c38a..0993d3322f1e6 100644 --- a/src/librustc/middle/trans/glue.rs +++ b/src/librustc/middle/trans/glue.rs @@ -339,7 +339,7 @@ pub fn make_visit_glue(bcx: @mut Block, v: ValueRef, t: ty::t) -> @mut Block { do with_scope(bcx, None, "visitor cleanup") |bcx| { let mut bcx = bcx; let (visitor_trait, object_ty) = match ty::visitor_object_ty(bcx.tcx(), - ty::re_static) { + ty::ReStatic) { Ok(pair) => pair, Err(s) => { bcx.tcx().sess.fatal(s); diff --git a/src/librustc/middle/trans/reflect.rs b/src/librustc/middle/trans/reflect.rs index 2f4fcfed20be9..0781f724d48c3 100644 --- a/src/librustc/middle/trans/reflect.rs +++ b/src/librustc/middle/trans/reflect.rs @@ -59,7 +59,7 @@ impl Reflector { // We're careful to not use first class aggregates here because that // will kick us off fast isel. (Issue #4352.) let bcx = self.bcx; - let str_vstore = ty::vstore_slice(ty::re_static); + let str_vstore = ty::vstore_slice(ty::ReStatic); let str_ty = ty::mk_estr(bcx.tcx(), str_vstore); let scratch = scratch_datum(bcx, str_ty, "", false); let len = C_uint(bcx.ccx(), s.len()); diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index a29591705844e..390c651ea7977 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -470,43 +470,45 @@ pub struct param_ty { /// Representation of regions: #[deriving(Clone, Eq, IterBytes, Encodable, Decodable, ToStr)] pub enum Region { - // Region bound in a type declaration (type/enum/struct/trait), - // which will be substituted when an instance of the type is accessed - re_type_bound(/* param id */ ast::NodeId, /*index*/ uint, ast::Ident), + // Region bound in a type or fn declaration which will be + // substituted 'early' -- that is, at the same time when type + // parameters are substituted. + ReEarlyBound(/* param id */ ast::NodeId, /*index*/ uint, ast::Ident), - // Region bound in a fn scope, which will be substituted when the - // fn is called. - re_fn_bound(/* binder_id */ ast::NodeId, bound_region), + // Region bound in a function scope, which will be substituted when the + // function is called. The first argument must be the `binder_id` of + // some enclosing function signature. + ReLateBound(/* binder_id */ ast::NodeId, BoundRegion), /// When checking a function body, the types of all arguments and so forth /// that refer to bound region parameters are modified to refer to free /// region parameters. - re_free(FreeRegion), + ReFree(FreeRegion), /// A concrete region naming some expression within the current function. - re_scope(NodeId), + ReScope(NodeId), /// Static data that has an "infinite" lifetime. Top in the region lattice. - re_static, + ReStatic, /// A region variable. Should not exist after typeck. - re_infer(InferRegion), + ReInfer(InferRegion), /// Empty lifetime is for data that is never accessed. - /// Bottom in the region lattice. We treat re_empty somewhat + /// Bottom in the region lattice. We treat ReEmpty somewhat /// specially; at least right now, we do not generate instances of /// it during the GLB computations, but rather /// generate an error instead. This is to improve error messages. - /// The only way to get an instance of re_empty is to have a region + /// The only way to get an instance of ReEmpty is to have a region /// variable with no constraints. - re_empty, + ReEmpty, } impl Region { pub fn is_bound(&self) -> bool { match self { - &ty::re_type_bound(*) => true, - &ty::re_fn_bound(*) => true, + &ty::ReEarlyBound(*) => true, + &ty::ReLateBound(*) => true, _ => false } } @@ -515,28 +517,28 @@ impl Region { #[deriving(Clone, Eq, TotalOrd, TotalEq, IterBytes, Encodable, Decodable, ToStr)] pub struct FreeRegion { scope_id: NodeId, - bound_region: bound_region + bound_region: BoundRegion } #[deriving(Clone, Eq, TotalEq, TotalOrd, IterBytes, Encodable, Decodable, ToStr)] -pub enum bound_region { +pub enum BoundRegion { /// An anonymous region parameter for a given fn (&T) - br_anon(uint), + BrAnon(uint), /// Named region parameters for functions (a in &'a T) /// /// The def-id is needed to distinguish free regions in /// the event of shadowing. - br_named(ast::DefId, ast::Ident), + BrNamed(ast::DefId, ast::Ident), /// Fresh bound identifiers created during GLB computations. - br_fresh(uint), + BrFresh(uint), } /** * Represents the values to use when substituting lifetime parameters. * If the value is `ErasedRegions`, then this subst is occurring during - * trans, and all region parameters will be replaced with `ty::re_static`. */ + * trans, and all region parameters will be replaced with `ty::ReStatic`. */ #[deriving(Clone, Eq, IterBytes)] pub enum RegionSubsts { ErasedRegions, @@ -701,8 +703,8 @@ pub enum type_err { terr_regions_does_not_outlive(Region, Region), terr_regions_not_same(Region, Region), terr_regions_no_overlap(Region, Region), - terr_regions_insufficiently_polymorphic(bound_region, Region), - terr_regions_overly_polymorphic(bound_region, Region), + terr_regions_insufficiently_polymorphic(BoundRegion, Region), + terr_regions_overly_polymorphic(BoundRegion, Region), terr_vstores_differ(terr_vstore_kind, expected_found), terr_trait_stores_differ(terr_vstore_kind, expected_found), terr_in_field(@type_err, ast::Ident), @@ -778,7 +780,7 @@ pub enum InferTy { #[deriving(Clone, Encodable, Decodable, IterBytes, ToStr)] pub enum InferRegion { ReVar(RegionVid), - ReSkolemized(uint, bound_region) + ReSkolemized(uint, BoundRegion) } impl cmp::Eq for InferRegion { @@ -1043,7 +1045,7 @@ pub fn mk_t(cx: ctxt, st: sty) -> t { fn rflags(r: Region) -> uint { (has_regions as uint) | { match r { - ty::re_infer(_) => needs_infer as uint, + ty::ReInfer(_) => needs_infer as uint, _ => 0u } } @@ -2148,7 +2150,7 @@ pub fn type_contents(cx: ctxt, ty: t) -> TypeContents { ast::MutMutable => TC::ReachesMutable | TC::OwnsAffine, ast::MutImmutable => TC::None, }; - b | (TC::ReachesBorrowed).when(region != ty::re_static) + b | (TC::ReachesBorrowed).when(region != ty::ReStatic) } fn closure_contents(cx: ctxt, cty: &ClosureTy) -> TypeContents { @@ -4220,12 +4222,12 @@ pub fn normalize_ty(cx: ctxt, t: t) -> t { fn fold_vstore(&mut self, vstore: vstore) -> vstore { match vstore { vstore_fixed(*) | vstore_uniq | vstore_box => vstore, - vstore_slice(_) => vstore_slice(re_static) + vstore_slice(_) => vstore_slice(ReStatic) } } fn fold_region(&mut self, _: ty::Region) -> ty::Region { - ty::re_static + ty::ReStatic } fn fold_substs(&mut self, @@ -4564,10 +4566,16 @@ pub fn hash_crate_independent(tcx: ctxt, t: t, local_hash: @str) -> u64 { let mut hash = SipState::new(0, 0); let region = |_hash: &mut SipState, r: Region| { match r { - re_static => {} - - re_empty | re_bound(*) | re_free(*) | re_scope(*) | re_infer(*) => + ReStatic => {} + + ReEmpty | + ReEarlyBound(*) | + ReLateBound(*) | + ReFree(*) | + ReStatic(*) | + ReInfer(*) => { tcx.sess.bug("non-static region found when hashing a type") + } } }; let vstore = |hash: &mut SipState, v: vstore| { @@ -4751,9 +4759,9 @@ pub fn construct_parameter_environment( // map bound 'a => free 'a let region_params = item_region_params.iter(). - map(|r| ty::re_free(ty::FreeRegion { + map(|r| ty::ReFree(ty::FreeRegion { scope_id: free_id, - bound_region: ty::br_named(r.def_id, r.ident)})). + bound_region: ty::BrNamed(r.def_id, r.ident)})). collect(); let free_substs = substs { diff --git a/src/librustc/middle/typeck/astconv.rs b/src/librustc/middle/typeck/astconv.rs index 0c0abaa5d76cf..5040c19158e0b 100644 --- a/src/librustc/middle/typeck/astconv.rs +++ b/src/librustc/middle/typeck/astconv.rs @@ -87,23 +87,23 @@ pub fn ast_region_to_region( } Some(&ast::DefStaticRegion) => { - ty::re_static + ty::ReStatic } - Some(&ast::DefFnBoundRegion(binder_id, _, id)) => { - ty::re_fn_bound(binder_id, ty::br_named(ast_util::local_def(id), - lifetime.ident)) + Some(&ast::DefLateBoundRegion(binder_id, _, id)) => { + ty::ReLateBound(binder_id, ty::BrNamed(ast_util::local_def(id), + lifetime.ident)) } - Some(&ast::DefTypeBoundRegion(index, id)) => { - ty::re_type_bound(id, index, lifetime.ident) + Some(&ast::DefEarlyBoundRegion(index, id)) => { + ty::ReEarlyBound(id, index, lifetime.ident) } Some(&ast::DefFreeRegion(scope_id, id)) => { - ty::re_free(ty::FreeRegion { + ty::ReFree(ty::FreeRegion { scope_id: scope_id, - bound_region: ty::br_named(ast_util::local_def(id), - lifetime.ident) + bound_region: ty::BrNamed(ast_util::local_def(id), + lifetime.ident) }) } }; @@ -133,7 +133,7 @@ pub fn opt_ast_region_to_region( debug!("optional region in illegal location"); this.tcx().sess.span_err( default_span, "missing lifetime specifier"); - ty::re_static + ty::ReStatic } Some(rs) => { @@ -190,7 +190,7 @@ fn ast_path_substs( match anon_regions { Some(v) => opt_vec::from(v), None => opt_vec::from(vec::from_fn(expected_num_region_params, - |_| ty::re_static)) // hokey + |_| ty::ReStatic)) // hokey } }; @@ -431,7 +431,7 @@ pub fn ast_ty_to_ty( let bounds = conv_builtin_bounds(this.tcx(), &f.bounds, match f.sigil { // Use corresponding trait store to figure out default bounds // if none were specified. - ast::BorrowedSigil => ty::RegionTraitStore(ty::re_empty), // dummy region + ast::BorrowedSigil => ty::RegionTraitStore(ty::ReEmpty), // dummy region ast::OwnedSigil => ty::UniqTraitStore, ast::ManagedSigil => ty::BoxTraitStore, }); @@ -713,7 +713,7 @@ pub fn ty_of_closure( ast::OwnedSigil | ast::ManagedSigil => { // @fn(), ~fn() default to static as the bound // on their upvars: - ty::re_static + ty::ReStatic } ast::BorrowedSigil => { // &fn() defaults as normal for an omitted lifetime: @@ -803,7 +803,7 @@ fn conv_builtin_bounds(tcx: ty::ctxt, ast_bounds: &Option { + (&None, ty::RegionTraitStore(ty::ReStatic)) => { let mut set = ty::EmptyBuiltinBounds(); set.add(ty::BoundStatic); set } // &'r Trait is sugar for &'r Trait:. diff --git a/src/librustc/middle/typeck/check/mod.rs b/src/librustc/middle/typeck/check/mod.rs index cf362384f3ade..ebe3c828262c2 100644 --- a/src/librustc/middle/typeck/check/mod.rs +++ b/src/librustc/middle/typeck/check/mod.rs @@ -438,7 +438,7 @@ pub fn check_fn(ccx: @mut CrateCtxt, let (_, opt_self_ty, fn_sig) = replace_bound_regions_in_fn_sig( tcx, opt_self_ty, fn_sig, - |br| ty::re_free(ty::FreeRegion {scope_id: body.id, + |br| ty::ReFree(ty::FreeRegion {scope_id: body.id, bound_region: br})); let opt_self_info = opt_self_info.map( @@ -931,9 +931,9 @@ pub fn compare_impl_method(tcx: ty::ctxt, collect(); let dummy_impl_regions: OptVec = impl_generics.region_param_defs.iter(). - map(|l| ty::re_free(ty::FreeRegion { + map(|l| ty::ReFree(ty::FreeRegion { scope_id: impl_m_body_id, - bound_region: ty::br_named(l.def_id, l.ident)})). + bound_region: ty::BrNamed(l.def_id, l.ident)})). collect(); let dummy_substs = ty::substs { tps: vec::append(dummy_impl_tps, dummy_method_tps), @@ -1090,7 +1090,7 @@ impl FnCtxt { } pub fn block_region(&self) -> ty::Region { - ty::re_scope(self.region_lb) + ty::ReScope(self.region_lb) } #[inline] @@ -1357,10 +1357,10 @@ pub fn check_lit(fcx: @mut FnCtxt, lit: @ast::lit) -> ty::t { let tcx = fcx.ccx.tcx; match lit.node { - ast::lit_str(*) => ty::mk_estr(tcx, ty::vstore_slice(ty::re_static)), + ast::lit_str(*) => ty::mk_estr(tcx, ty::vstore_slice(ty::ReStatic)), ast::lit_binary(*) => { ty::mk_evec(tcx, ty::mt{ ty: ty::mk_u8(), mutbl: ast::MutImmutable }, - ty::vstore_slice(ty::re_static)) + ty::vstore_slice(ty::ReStatic)) } ast::lit_char(_) => ty::mk_char(), ast::lit_int(_, t) => ty::mk_mach_int(t), @@ -3925,19 +3925,19 @@ pub fn check_intrinsic_type(ccx: @mut CrateCtxt, it: @ast::foreign_item) { //We only care about the operation here match split[1] { "cxchg" => (0, ~[ty::mk_mut_rptr(tcx, - ty::re_fn_bound(it.id, ty::br_anon(0)), + ty::ReLateBound(it.id, ty::BrAnon(0)), ty::mk_int()), ty::mk_int(), ty::mk_int() ], ty::mk_int()), "load" => (0, ~[ - ty::mk_imm_rptr(tcx, ty::re_fn_bound(it.id, ty::br_anon(0)), ty::mk_int()) + ty::mk_imm_rptr(tcx, ty::ReLateBound(it.id, ty::BrAnon(0)), ty::mk_int()) ], ty::mk_int()), "store" => (0, ~[ - ty::mk_mut_rptr(tcx, ty::re_fn_bound(it.id, ty::br_anon(0)), ty::mk_int()), + ty::mk_mut_rptr(tcx, ty::ReLateBound(it.id, ty::BrAnon(0)), ty::mk_int()), ty::mk_int() ], ty::mk_nil()), @@ -3945,7 +3945,7 @@ pub fn check_intrinsic_type(ccx: @mut CrateCtxt, it: @ast::foreign_item) { "xchg" | "xadd" | "xsub" | "and" | "nand" | "or" | "xor" | "max" | "min" | "umax" | "umin" => { (0, ~[ty::mk_mut_rptr(tcx, - ty::re_fn_bound(it.id, ty::br_anon(0)), + ty::ReLateBound(it.id, ty::BrAnon(0)), ty::mk_int()), ty::mk_int() ], ty::mk_int()) } "fence" => { @@ -3971,7 +3971,7 @@ pub fn check_intrinsic_type(ccx: @mut CrateCtxt, it: @ast::foreign_item) { "move_val" | "move_val_init" => { (1u, ~[ - ty::mk_mut_rptr(tcx, ty::re_fn_bound(it.id, ty::br_anon(0)), param(ccx, 0)), + ty::mk_mut_rptr(tcx, ty::ReLateBound(it.id, ty::BrAnon(0)), param(ccx, 0)), param(ccx, 0u) ], ty::mk_nil()) @@ -3983,7 +3983,7 @@ pub fn check_intrinsic_type(ccx: @mut CrateCtxt, it: @ast::foreign_item) { "atomic_xchg_rel" | "atomic_xadd_rel" | "atomic_xsub_rel" => { (0, ~[ - ty::mk_mut_rptr(tcx, ty::re_fn_bound(it.id, ty::br_anon(0)), ty::mk_int()), + ty::mk_mut_rptr(tcx, ty::ReLateBound(it.id, ty::BrAnon(0)), ty::mk_int()), ty::mk_int() ], ty::mk_int()) @@ -4006,7 +4006,7 @@ pub fn check_intrinsic_type(ccx: @mut CrateCtxt, it: @ast::foreign_item) { Ok(t) => t, Err(s) => { tcx.sess.span_fatal(it.span, s); } }; - let region = ty::re_fn_bound(it.id, ty::br_anon(0)); + let region = ty::ReLateBound(it.id, ty::BrAnon(0)); let visitor_object_ty = match ty::visitor_object_ty(tcx, region) { Ok((_, vot)) => vot, Err(s) => { tcx.sess.span_fatal(it.span, s); } diff --git a/src/librustc/middle/typeck/check/regionck.rs b/src/librustc/middle/typeck/check/regionck.rs index cd94e040ac371..b21d36777c293 100644 --- a/src/librustc/middle/typeck/check/regionck.rs +++ b/src/librustc/middle/typeck/check/regionck.rs @@ -29,7 +29,7 @@ this point a bit better. use middle::freevars::get_freevars; -use middle::ty::{re_scope}; +use middle::ty::{ReScope}; use middle::ty; use middle::typeck::check::FnCtxt; use middle::typeck::check::regionmanip::relate_nested_regions; @@ -64,7 +64,7 @@ fn encl_region_of_def(fcx: @mut FnCtxt, def: ast::Def) -> ty::Region { DefUpvar(_, subdef, closure_id, body_id) => { match ty::ty_closure_sigil(fcx.node_ty(closure_id)) { BorrowedSigil => encl_region_of_def(fcx, *subdef), - ManagedSigil | OwnedSigil => re_scope(body_id) + ManagedSigil | OwnedSigil => ReScope(body_id) } } _ => { @@ -317,7 +317,7 @@ fn visit_expr(rcx: &mut Rcx, expr: @ast::Expr) { // // FIXME(#6268) remove to support nested method calls constrain_regions_in_type_of_node( - rcx, expr.id, ty::re_scope(expr.id), + rcx, expr.id, ty::ReScope(expr.id), infer::AutoBorrow(expr.span)); } } @@ -416,7 +416,7 @@ fn visit_expr(rcx: &mut Rcx, expr: @ast::Expr) { // // FIXME(#6268) nested method calls requires that this rule change let ty0 = rcx.resolve_node_type(expr.id); - constrain_regions_in_type(rcx, ty::re_scope(expr.id), + constrain_regions_in_type(rcx, ty::ReScope(expr.id), infer::AddrOf(expr.span), ty0); visit::walk_expr(rcx, expr, ()); } @@ -474,7 +474,7 @@ fn check_expr_fn_block(rcx: &mut Rcx, // (since otherwise that would require // infinite stack). constrain_free_variables(rcx, region, expr); - let repeating_scope = ty::re_scope(rcx.repeating_scope); + let repeating_scope = ty::ReScope(rcx.repeating_scope); rcx.fcx.mk_subr(true, infer::InfStackClosure(expr.span), region, repeating_scope); } @@ -500,7 +500,7 @@ fn constrain_callee(rcx: &mut Rcx, call_expr: @ast::Expr, callee_expr: @ast::Expr) { - let call_region = ty::re_scope(call_expr.id); + let call_region = ty::ReScope(call_expr.id); let callee_ty = rcx.resolve_node_type(callee_id); match ty::get(callee_ty).sty { @@ -555,7 +555,7 @@ fn constrain_call(rcx: &mut Rcx, // // FIXME(#6268) to support nested method calls, should be callee_id let callee_scope = call_expr.id; - let callee_region = ty::re_scope(callee_scope); + let callee_region = ty::ReScope(callee_scope); for &arg_expr in arg_exprs.iter() { debug!("Argument"); @@ -604,7 +604,7 @@ fn constrain_derefs(rcx: &mut Rcx, * the deref expr. */ let tcx = rcx.fcx.tcx(); - let r_deref_expr = ty::re_scope(deref_expr.id); + let r_deref_expr = ty::ReScope(deref_expr.id); for i in range(0u, derefs) { debug!("constrain_derefs(deref_expr=?, derefd_ty={}, derefs={:?}/{:?}", rcx.fcx.infcx().ty_to_str(derefd_ty), @@ -650,7 +650,7 @@ fn constrain_index(rcx: &mut Rcx, debug!("constrain_index(index_expr=?, indexed_ty={}", rcx.fcx.infcx().ty_to_str(indexed_ty)); - let r_index_expr = ty::re_scope(index_expr.id); + let r_index_expr = ty::ReScope(index_expr.id); match ty::get(indexed_ty).sty { ty::ty_estr(ty::vstore_slice(r_ptr)) | ty::ty_evec(_, ty::vstore_slice(r_ptr)) => { @@ -912,7 +912,7 @@ pub mod guarantor { let expr_cat = categorize(rcx, expr); debug!("guarantor::for_by_ref(expr={:?}, callee_scope={:?}) category={:?}", expr.id, callee_scope, expr_cat); - let minimum_lifetime = ty::re_scope(callee_scope); + let minimum_lifetime = ty::ReScope(callee_scope); for guarantor in expr_cat.guarantor.iter() { mk_subregion_due_to_derefence(rcx, expr.span, minimum_lifetime, *guarantor); diff --git a/src/librustc/middle/typeck/check/regionmanip.rs b/src/librustc/middle/typeck/check/regionmanip.rs index ea7b2faf27342..a73aa46fbec2b 100644 --- a/src/librustc/middle/typeck/check/regionmanip.rs +++ b/src/librustc/middle/typeck/check/regionmanip.rs @@ -23,8 +23,8 @@ pub fn replace_bound_regions_in_fn_sig( tcx: ty::ctxt, opt_self_ty: Option, fn_sig: &ty::FnSig, - mapf: &fn(ty::bound_region) -> ty::Region) - -> (HashMap, Option, ty::FnSig) + mapf: &fn(ty::BoundRegion) -> ty::Region) + -> (HashMap, Option, ty::FnSig) { debug!("replace_bound_regions_in_fn_sig(self_ty={}, fn_sig={})", opt_self_ty.repr(tcx), @@ -35,7 +35,7 @@ pub fn replace_bound_regions_in_fn_sig( let mut f = ty_fold::RegionFolder::regions(tcx, |r| { debug!("region r={}", r.to_str()); match r { - ty::re_fn_bound(s, br) if s == fn_sig.binder_id => { + ty::ReLateBound(s, br) if s == fn_sig.binder_id => { *map.find_or_insert_with(br, |_| mapf(br)) } _ => r @@ -175,7 +175,7 @@ pub fn relate_free_regions( debug!("relate_free_regions(t={})", ppaux::ty_to_str(tcx, t)); relate_nested_regions(tcx, None, t, |a, b| { match (&a, &b) { - (&ty::re_free(free_a), &ty::re_free(free_b)) => { + (&ty::ReFree(free_a), &ty::ReFree(free_b)) => { tcx.region_maps.relate_free_regions(free_a, free_b); } _ => {} diff --git a/src/librustc/middle/typeck/check/vtable.rs b/src/librustc/middle/typeck/check/vtable.rs index ae76c9ed6dd49..996157df2e299 100644 --- a/src/librustc/middle/typeck/check/vtable.rs +++ b/src/librustc/middle/typeck/check/vtable.rs @@ -480,7 +480,7 @@ fn fixup_substs(vcx: &VtableContext, // use a dummy type just to package up the substs that need fixing up let t = ty::mk_trait(tcx, id, substs, - ty::RegionTraitStore(ty::re_static), + ty::RegionTraitStore(ty::ReStatic), ast::MutImmutable, ty::EmptyBuiltinBounds()); do fixup_ty(vcx, location_info, t, is_early).map |t_f| { diff --git a/src/librustc/middle/typeck/collect.rs b/src/librustc/middle/typeck/collect.rs index 7cf004be5e2a5..e55005d62e912 100644 --- a/src/librustc/middle/typeck/collect.rs +++ b/src/librustc/middle/typeck/collect.rs @@ -282,8 +282,8 @@ pub fn ensure_trait_methods(ccx: &CrateCtxt, // Convert the regions 'a, 'b, 'c defined on the trait into // bound regions on the fn. let rps_from_trait = trait_ty_generics.region_param_defs.iter().map(|d| { - ty::re_fn_bound(m.fty.sig.binder_id, - ty::br_named(d.def_id, d.ident)) + ty::ReLateBound(m.fty.sig.binder_id, + ty::BrNamed(d.def_id, d.ident)) }).collect(); // build up the substitution from @@ -964,7 +964,7 @@ pub fn mk_item_substs(ccx: &CrateCtxt, let regions: OptVec = ty_generics.region_param_defs.iter().enumerate().map( - |(i, l)| ty::re_type_bound(l.def_id.node, i, l.ident)).collect(); + |(i, l)| ty::ReEarlyBound(l.def_id.node, i, l.ident)).collect(); substs {regions: ty::NonerasedRegions(regions), self_ty: self_ty, diff --git a/src/librustc/middle/typeck/infer/glb.rs b/src/librustc/middle/typeck/infer/glb.rs index 78e0bd17ecaa8..9febef1c7c399 100644 --- a/src/librustc/middle/typeck/infer/glb.rs +++ b/src/librustc/middle/typeck/infer/glb.rs @@ -161,7 +161,7 @@ impl Combine for Glb { snapshot: uint, new_vars: &[RegionVid], new_binder_id: NodeId, - a_map: &HashMap, + a_map: &HashMap, a_vars: &[RegionVid], b_vars: &[RegionVid], r0: ty::Region) -> ty::Region { @@ -228,13 +228,13 @@ impl Combine for Glb { } fn rev_lookup(this: &Glb, - a_map: &HashMap, + a_map: &HashMap, new_binder_id: NodeId, r: ty::Region) -> ty::Region { for (a_br, a_r) in a_map.iter() { if *a_r == r { - return ty::re_fn_bound(new_binder_id, *a_br); + return ty::ReLateBound(new_binder_id, *a_br); } } this.infcx.tcx.sess.span_bug( diff --git a/src/librustc/middle/typeck/infer/lattice.rs b/src/librustc/middle/typeck/infer/lattice.rs index 9aaa4be1181f7..04bf5fda7258d 100644 --- a/src/librustc/middle/typeck/infer/lattice.rs +++ b/src/librustc/middle/typeck/infer/lattice.rs @@ -522,10 +522,10 @@ pub fn lattice_var_and_t(this: &T, - map: &HashMap) + map: &HashMap) -> ~[RegionVid] { map.iter().map(|(_, r)| match *r { - ty::re_infer(ty::ReVar(r)) => { r } + ty::ReInfer(ty::ReVar(r)) => { r } r => { this.infcx().tcx.sess.span_bug( this.trace().origin.span(), @@ -536,7 +536,7 @@ pub fn var_ids(this: &T, pub fn is_var_in_set(new_vars: &[RegionVid], r: ty::Region) -> bool { match r { - ty::re_infer(ty::ReVar(ref v)) => new_vars.iter().any(|x| x == v), + ty::ReInfer(ty::ReVar(ref v)) => new_vars.iter().any(|x| x == v), _ => false } } diff --git a/src/librustc/middle/typeck/infer/lub.rs b/src/librustc/middle/typeck/infer/lub.rs index ad649f379b58c..b826310df7bff 100644 --- a/src/librustc/middle/typeck/infer/lub.rs +++ b/src/librustc/middle/typeck/infer/lub.rs @@ -149,7 +149,7 @@ impl Combine for Lub { snapshot: uint, new_vars: &[RegionVid], new_scope: NodeId, - a_map: &HashMap, + a_map: &HashMap, r0: ty::Region) -> ty::Region { // Regions that pre-dated the LUB computation stay as they are. @@ -182,7 +182,7 @@ impl Combine for Lub { debug!("generalize_region(r0={:?}): \ replacing with {:?}, tainted={:?}", r0, *a_br, tainted); - return ty::re_fn_bound(new_scope, *a_br); + return ty::ReLateBound(new_scope, *a_br); } } diff --git a/src/librustc/middle/typeck/infer/mod.rs b/src/librustc/middle/typeck/infer/mod.rs index 121b32f4145a4..eafc7e262f191 100644 --- a/src/librustc/middle/typeck/infer/mod.rs +++ b/src/librustc/middle/typeck/infer/mod.rs @@ -216,11 +216,11 @@ pub enum RegionVariableOrigin { // Region variables created for bound regions // in a function or method that is called - BoundRegionInFnCall(Span, ty::bound_region), + BoundRegionInFnCall(Span, ty::BoundRegion), // Region variables created for bound regions // when doing subtyping/lub/glb computations - BoundRegionInFnType(Span, ty::bound_region), + BoundRegionInFnType(Span, ty::BoundRegion), BoundRegionInTypeOrImpl(Span), @@ -638,7 +638,7 @@ impl InferCtxt { } pub fn next_region_var(&mut self, origin: RegionVariableOrigin) -> ty::Region { - ty::re_infer(ty::ReVar(self.region_vars.new_region_var(origin))) + ty::ReInfer(ty::ReVar(self.region_vars.new_region_var(origin))) } pub fn next_region_vars(&mut self, @@ -798,7 +798,7 @@ impl InferCtxt { trace: TypeTrace, fsig: &ty::FnSig) -> (ty::FnSig, - HashMap) { let (map, _, fn_sig) = replace_bound_regions_in_fn_sig(self.tcx, None, fsig, |br| { @@ -933,13 +933,13 @@ impl Repr for RegionVariableOrigin { AddrOfSlice(a) => format!("AddrOfSlice({})", a.repr(tcx)), Autoref(a) => format!("Autoref({})", a.repr(tcx)), Coercion(a) => format!("Coercion({})", a.repr(tcx)), - BoundRegionInFnCall(a, b) => format!("BoundRegionInFnCall({},{})", + BoundRegionInFnCall(a, b) => format!("bound_regionInFnCall({},{})", a.repr(tcx), b.repr(tcx)), - BoundRegionInFnType(a, b) => format!("BoundRegionInFnType({},{})", + BoundRegionInFnType(a, b) => format!("bound_regionInFnType({},{})", a.repr(tcx), b.repr(tcx)), - BoundRegionInTypeOrImpl(a) => format!("BoundRegionInTypeOrImpl({})", + BoundRegionInTypeOrImpl(a) => format!("bound_regionInTypeOrImpl({})", a.repr(tcx)), - BoundRegionInCoherence => format!("BoundRegionInCoherence"), + BoundRegionInCoherence => format!("bound_regionInCoherence"), } } } diff --git a/src/librustc/middle/typeck/infer/region_inference/mod.rs b/src/librustc/middle/typeck/infer/region_inference/mod.rs index effd34da0de9d..e613aa4ba28de 100644 --- a/src/librustc/middle/typeck/infer/region_inference/mod.rs +++ b/src/librustc/middle/typeck/infer/region_inference/mod.rs @@ -13,9 +13,9 @@ use middle::ty; use middle::ty::{FreeRegion, Region, RegionVid}; -use middle::ty::{re_empty, re_static, re_infer, re_free, re_type_bound, - re_fn_bound}; -use middle::ty::{re_scope, ReVar, ReSkolemized, br_fresh}; +use middle::ty::{ReEmpty, ReStatic, ReInfer, ReFree, ReEarlyBound, + ReLateBound}; +use middle::ty::{ReScope, ReVar, ReSkolemized, BrFresh}; use middle::typeck::infer::cres; use middle::typeck::infer::{RegionVariableOrigin, SubregionOrigin}; use middle::typeck::infer; @@ -187,10 +187,10 @@ impl RegionVarBindings { return vid; } - pub fn new_skolemized(&mut self, br: ty::bound_region) -> Region { + pub fn new_skolemized(&mut self, br: ty::BoundRegion) -> Region { let sc = self.skolemization_count; self.skolemization_count += 1; - re_infer(ReSkolemized(sc, br)) + ReInfer(ReSkolemized(sc, br)) } pub fn new_bound(&mut self, binder_id: ast::NodeId) -> Region { @@ -219,7 +219,7 @@ impl RegionVarBindings { self.tcx.sess.bug("Rollover in RegionInference new_bound()"); } - re_fn_bound(binder_id, br_fresh(sc)) + ReLateBound(binder_id, BrFresh(sc)) } pub fn add_constraint(&mut self, @@ -246,23 +246,23 @@ impl RegionVarBindings { debug!("RegionVarBindings: make_subregion({:?}, {:?})", sub, sup); match (sub, sup) { - (re_type_bound(*), _) | - (re_fn_bound(*), _) | - (_, re_type_bound(*)) | - (_, re_fn_bound(*)) => { + (ReEarlyBound(*), _) | + (ReLateBound(*), _) | + (_, ReEarlyBound(*)) | + (_, ReLateBound(*)) => { self.tcx.sess.span_bug( origin.span(), format!("Cannot relate bound region: {} <= {}", sub.repr(self.tcx), sup.repr(self.tcx))); } - (re_infer(ReVar(sub_id)), re_infer(ReVar(sup_id))) => { + (ReInfer(ReVar(sub_id)), ReInfer(ReVar(sup_id))) => { self.add_constraint(ConstrainVarSubVar(sub_id, sup_id), origin); } - (r, re_infer(ReVar(sup_id))) => { + (r, ReInfer(ReVar(sup_id))) => { self.add_constraint(ConstrainRegSubVar(r, sup_id), origin); } - (re_infer(ReVar(sub_id)), r) => { + (ReInfer(ReVar(sub_id)), r) => { self.add_constraint(ConstrainVarSubReg(sub_id, r), origin); } _ => { @@ -281,8 +281,8 @@ impl RegionVarBindings { debug!("RegionVarBindings: lub_regions({:?}, {:?})", a, b); match (a, b) { - (re_static, _) | (_, re_static) => { - re_static // nothing lives longer than static + (ReStatic, _) | (_, ReStatic) => { + ReStatic // nothing lives longer than static } _ => { @@ -304,7 +304,7 @@ impl RegionVarBindings { debug!("RegionVarBindings: glb_regions({:?}, {:?})", a, b); match (a, b) { - (re_static, r) | (r, re_static) => { + (ReStatic, r) | (r, ReStatic) => { // static lives longer than everything else r } @@ -333,13 +333,13 @@ impl RegionVarBindings { Value(r) => r, NoValue => { - // No constraints, return ty::re_empty - re_empty + // No constraints, return ty::ReEmpty + ReEmpty } ErrorValue => { // An error that has previously been reported. - re_static + ReStatic } } } @@ -366,7 +366,7 @@ impl RegionVarBindings { let vars = TwoRegions { a: a, b: b }; match self.combine_map(t).find(&vars) { Some(&c) => { - return re_infer(ReVar(c)); + return ReInfer(ReVar(c)); } None => {} } @@ -375,10 +375,10 @@ impl RegionVarBindings { if self.in_snapshot() { self.undo_log.push(AddCombination(t, vars)); } - relate(self, a, re_infer(ReVar(c))); - relate(self, b, re_infer(ReVar(c))); + relate(self, a, ReInfer(ReVar(c))); + relate(self, b, ReInfer(ReVar(c))); debug!("combine_vars() c={:?}", c); - re_infer(ReVar(c)) + ReInfer(ReVar(c)) } pub fn vars_created_since_snapshot(&mut self, snapshot: uint) @@ -421,14 +421,14 @@ impl RegionVarBindings { // nb: can't use uint::range() here as we move result_set let regs = match self.undo_log[undo_index] { AddConstraint(ConstrainVarSubVar(ref a, ref b)) => { - Some((re_infer(ReVar(*a)), - re_infer(ReVar(*b)))) + Some((ReInfer(ReVar(*a)), + ReInfer(ReVar(*b)))) } AddConstraint(ConstrainRegSubVar(ref a, ref b)) => { - Some((*a, re_infer(ReVar(*b)))) + Some((*a, ReInfer(ReVar(*b)))) } AddConstraint(ConstrainVarSubReg(ref a, ref b)) => { - Some((re_infer(ReVar(*a)), *b)) + Some((ReInfer(ReVar(*a)), *b)) } AddConstraint(ConstrainRegSubReg(a, b)) => { Some((a, b)) @@ -495,33 +495,33 @@ impl RegionVarBindings { fn lub_concrete_regions(&self, a: Region, b: Region) -> Region { match (a, b) { - (re_fn_bound(*), _) | - (_, re_fn_bound(*)) | - (re_type_bound(*), _) | - (_, re_type_bound(*)) => { + (ReLateBound(*), _) | + (_, ReLateBound(*)) | + (ReEarlyBound(*), _) | + (_, ReEarlyBound(*)) => { self.tcx.sess.bug( format!("Cannot relate bound region: LUB({}, {})", a.repr(self.tcx), b.repr(self.tcx))); } - (re_static, _) | (_, re_static) => { - re_static // nothing lives longer than static + (ReStatic, _) | (_, ReStatic) => { + ReStatic // nothing lives longer than static } - (re_empty, r) | (r, re_empty) => { + (ReEmpty, r) | (r, ReEmpty) => { r // everything lives longer than empty } - (re_infer(ReVar(v_id)), _) | (_, re_infer(ReVar(v_id))) => { + (ReInfer(ReVar(v_id)), _) | (_, ReInfer(ReVar(v_id))) => { self.tcx.sess.span_bug( self.var_origins[v_id.to_uint()].span(), format!("lub_concrete_regions invoked with \ non-concrete regions: {:?}, {:?}", a, b)); } - (f @ re_free(ref fr), re_scope(s_id)) | - (re_scope(s_id), f @ re_free(ref fr)) => { + (f @ ReFree(ref fr), ReScope(s_id)) | + (ReScope(s_id), f @ ReFree(ref fr)) => { // A "free" region can be interpreted as "some region // at least as big as the block fr.scope_id". So, we can // reasonably compare free regions and scopes: @@ -534,30 +534,30 @@ impl RegionVarBindings { // otherwise, we don't know what the free region is, // so we must conservatively say the LUB is static: - _ => re_static + _ => ReStatic } } - (re_scope(a_id), re_scope(b_id)) => { + (ReScope(a_id), ReScope(b_id)) => { // The region corresponding to an outer block is a // subtype of the region corresponding to an inner // block. let rm = self.tcx.region_maps; match rm.nearest_common_ancestor(a_id, b_id) { - Some(r_id) => re_scope(r_id), - _ => re_static + Some(r_id) => ReScope(r_id), + _ => ReStatic } } - (re_free(ref a_fr), re_free(ref b_fr)) => { + (ReFree(ref a_fr), ReFree(ref b_fr)) => { self.lub_free_regions(a_fr, b_fr) } // For these types, we cannot define any additional // relationship: - (re_infer(ReSkolemized(*)), _) | - (_, re_infer(ReSkolemized(*))) => { - if a == b {a} else {re_static} + (ReInfer(ReSkolemized(*)), _) | + (_, ReInfer(ReSkolemized(*))) => { + if a == b {a} else {ReStatic} } } } @@ -575,7 +575,7 @@ impl RegionVarBindings { return match a.cmp(b) { Less => helper(self, a, b), Greater => helper(self, b, a), - Equal => ty::re_free(*a) + Equal => ty::ReFree(*a) }; fn helper(this: &RegionVarBindings, @@ -584,11 +584,11 @@ impl RegionVarBindings { { let rm = this.tcx.region_maps; if rm.sub_free_region(*a, *b) { - ty::re_free(*b) + ty::ReFree(*b) } else if rm.sub_free_region(*b, *a) { - ty::re_free(*a) + ty::ReFree(*a) } else { - ty::re_static + ty::ReStatic } } } @@ -599,36 +599,36 @@ impl RegionVarBindings { -> cres { debug!("glb_concrete_regions({:?}, {:?})", a, b); match (a, b) { - (re_fn_bound(*), _) | - (_, re_fn_bound(*)) | - (re_type_bound(*), _) | - (_, re_type_bound(*)) => { + (ReLateBound(*), _) | + (_, ReLateBound(*)) | + (ReEarlyBound(*), _) | + (_, ReEarlyBound(*)) => { self.tcx.sess.bug( format!("Cannot relate bound region: GLB({}, {})", a.repr(self.tcx), b.repr(self.tcx))); } - (re_static, r) | (r, re_static) => { + (ReStatic, r) | (r, ReStatic) => { // static lives longer than everything else Ok(r) } - (re_empty, _) | (_, re_empty) => { + (ReEmpty, _) | (_, ReEmpty) => { // nothing lives shorter than everything else - Ok(re_empty) + Ok(ReEmpty) } - (re_infer(ReVar(v_id)), _) | - (_, re_infer(ReVar(v_id))) => { + (ReInfer(ReVar(v_id)), _) | + (_, ReInfer(ReVar(v_id))) => { self.tcx.sess.span_bug( self.var_origins[v_id.to_uint()].span(), format!("glb_concrete_regions invoked with \ non-concrete regions: {:?}, {:?}", a, b)); } - (re_free(ref fr), s @ re_scope(s_id)) | - (s @ re_scope(s_id), re_free(ref fr)) => { + (ReFree(ref fr), s @ ReScope(s_id)) | + (s @ ReScope(s_id), ReFree(ref fr)) => { // Free region is something "at least as big as // `fr.scope_id`." If we find that the scope `fr.scope_id` is bigger // than the scope `s_id`, then we can say that the GLB @@ -641,18 +641,18 @@ impl RegionVarBindings { } } - (re_scope(a_id), re_scope(b_id)) => { + (ReScope(a_id), ReScope(b_id)) => { self.intersect_scopes(a, b, a_id, b_id) } - (re_free(ref a_fr), re_free(ref b_fr)) => { + (ReFree(ref a_fr), ReFree(ref b_fr)) => { self.glb_free_regions(a_fr, b_fr) } // For these types, we cannot define any additional // relationship: - (re_infer(ReSkolemized(*)), _) | - (_, re_infer(ReSkolemized(*))) => { + (ReInfer(ReSkolemized(*)), _) | + (_, ReInfer(ReSkolemized(*))) => { if a == b { Ok(a) } else { @@ -675,7 +675,7 @@ impl RegionVarBindings { return match a.cmp(b) { Less => helper(self, a, b), Greater => helper(self, b, a), - Equal => Ok(ty::re_free(*a)) + Equal => Ok(ty::ReFree(*a)) }; fn helper(this: &RegionVarBindings, @@ -684,11 +684,11 @@ impl RegionVarBindings { { let rm = this.tcx.region_maps; if rm.sub_free_region(*a, *b) { - Ok(ty::re_free(*a)) + Ok(ty::ReFree(*a)) } else if rm.sub_free_region(*b, *a) { - Ok(ty::re_free(*b)) + Ok(ty::ReFree(*b)) } else { - this.intersect_scopes(ty::re_free(*a), ty::re_free(*b), + this.intersect_scopes(ty::ReFree(*a), ty::ReFree(*b), a.scope_id, b.scope_id) } } @@ -715,8 +715,8 @@ impl RegionVarBindings { scope_a, scope_b, region_a, region_b); let rm = self.tcx.region_maps; match rm.nearest_common_ancestor(scope_a, scope_b) { - Some(r_id) if scope_a == r_id => Ok(re_scope(scope_b)), - Some(r_id) if scope_b == r_id => Ok(re_scope(scope_a)), + Some(r_id) if scope_a == r_id => Ok(ReScope(scope_b)), + Some(r_id) if scope_b == r_id => Ok(ReScope(scope_a)), _ => Err(ty::terr_regions_no_overlap(region_a, region_b)) } } diff --git a/src/librustc/middle/typeck/infer/resolve.rs b/src/librustc/middle/typeck/infer/resolve.rs index 84f3d9c69379b..168d8a57c7fec 100644 --- a/src/librustc/middle/typeck/infer/resolve.rs +++ b/src/librustc/middle/typeck/infer/resolve.rs @@ -192,21 +192,21 @@ impl ResolveState { pub fn resolve_region(&mut self, orig: ty::Region) -> ty::Region { debug!("Resolve_region({})", orig.inf_str(self.infcx)); match orig { - ty::re_infer(ty::ReVar(rid)) => self.resolve_region_var(rid), + ty::ReInfer(ty::ReVar(rid)) => self.resolve_region_var(rid), _ => orig } } pub fn resolve_region_var(&mut self, rid: RegionVid) -> ty::Region { if !self.should(resolve_rvar) { - return ty::re_infer(ty::ReVar(rid)); + return ty::ReInfer(ty::ReVar(rid)); } self.infcx.region_vars.resolve_var(rid) } pub fn assert_not_rvar(&mut self, rid: RegionVid, r: ty::Region) { match r { - ty::re_infer(ty::ReVar(rid2)) => { + ty::ReInfer(ty::ReVar(rid2)) => { self.err = Some(region_var_bound_by_region_var(rid, rid2)); } _ => { } diff --git a/src/librustc/middle/typeck/infer/sub.rs b/src/librustc/middle/typeck/infer/sub.rs index 802d635a3f0c0..117b100005a01 100644 --- a/src/librustc/middle/typeck/infer/sub.rs +++ b/src/librustc/middle/typeck/infer/sub.rs @@ -192,7 +192,7 @@ impl Combine for Sub { // Each skolemized should only be relatable to itself // or new variables: match *tainted_region { - ty::re_infer(ty::ReVar(ref vid)) => { + ty::ReInfer(ty::ReVar(ref vid)) => { if new_vars.iter().any(|x| x == vid) { continue; } } _ => { diff --git a/src/librustc/middle/typeck/infer/test.rs b/src/librustc/middle/typeck/infer/test.rs index d7a00ebf0e940..7c56594d26755 100644 --- a/src/librustc/middle/typeck/infer/test.rs +++ b/src/librustc/middle/typeck/infer/test.rs @@ -188,7 +188,7 @@ impl Env { meta: FnMeta {purity: ast::impure_fn, proto: ast::ProtoBare, onceness: ast::Many, - region: ty::re_static, + region: ty::ReStatic, bounds: @~[]}, sig: FnSig { inputs: inputs, @@ -203,22 +203,22 @@ impl Env { } pub fn t_rptr_bound(&self, id: uint) -> ty::t { - ty::mk_imm_rptr(self.tcx, ty::re_bound(ty::br_anon(id)), self.t_int()) + ty::mk_imm_rptr(self.tcx, ty::re_bound(ty::BrAnon(id)), self.t_int()) } pub fn t_rptr_scope(&self, id: ast::node_id) -> ty::t { - ty::mk_imm_rptr(self.tcx, ty::re_scope(id), self.t_int()) + ty::mk_imm_rptr(self.tcx, ty::ReScope(id), self.t_int()) } pub fn t_rptr_free(&self, nid: ast::node_id, id: uint) -> ty::t { ty::mk_imm_rptr(self.tcx, - ty::re_free(ty::FreeRegion {scope_id: nid, - bound_region: ty::br_anon(id)}), + ty::ReFree(ty::FreeRegion {scope_id: nid, + bound_region: ty::BrAnon(id)}), self.t_int()) } pub fn t_rptr_static(&self) -> ty::t { - ty::mk_imm_rptr(self.tcx, ty::re_static, self.t_int()) + ty::mk_imm_rptr(self.tcx, ty::ReStatic, self.t_int()) } pub fn lub() -> Lub { Lub(self.infcx.combine_fields(true, dummy_sp())) } diff --git a/src/librustc/middle/typeck/mod.rs b/src/librustc/middle/typeck/mod.rs index ed6c810e52cd6..63ddc9addc55e 100644 --- a/src/librustc/middle/typeck/mod.rs +++ b/src/librustc/middle/typeck/mod.rs @@ -317,19 +317,19 @@ pub fn require_same_types( // a list of mapping from in-scope-region-names ("isr") to the // corresponding ty::Region -pub type isr_alist = @List<(ty::bound_region, ty::Region)>; +pub type isr_alist = @List<(ty::BoundRegion, ty::Region)>; trait get_and_find_region { - fn get(&self, br: ty::bound_region) -> ty::Region; - fn find(&self, br: ty::bound_region) -> Option; + fn get(&self, br: ty::BoundRegion) -> ty::Region; + fn find(&self, br: ty::BoundRegion) -> Option; } impl get_and_find_region for isr_alist { - fn get(&self, br: ty::bound_region) -> ty::Region { + fn get(&self, br: ty::BoundRegion) -> ty::Region { self.find(br).unwrap() } - fn find(&self, br: ty::bound_region) -> Option { + fn find(&self, br: ty::BoundRegion) -> Option { let mut ret = None; do list::each(*self) |isr| { let (isr_br, isr_r) = *isr; diff --git a/src/librustc/middle/typeck/rscope.rs b/src/librustc/middle/typeck/rscope.rs index 2c48eb04ee6dc..3d095d1e8a5e8 100644 --- a/src/librustc/middle/typeck/rscope.rs +++ b/src/librustc/middle/typeck/rscope.rs @@ -56,8 +56,8 @@ impl RegionScope for BindingRscope { -> Option<~[ty::Region]> { let idx = *self.anon_bindings; *self.anon_bindings += count; - Some(vec::from_fn(count, |i| ty::re_fn_bound(self.binder_id, - ty::br_anon(idx + i)))) + Some(vec::from_fn(count, |i| ty::ReLateBound(self.binder_id, + ty::BrAnon(idx + i)))) } } @@ -65,5 +65,5 @@ pub fn bound_type_regions(defs: &[ty::RegionParameterDef]) -> OptVec { assert!(defs.iter().all(|def| def.def_id.crate == ast::LOCAL_CRATE)); defs.iter().enumerate().map( - |(i, def)| ty::re_type_bound(def.def_id.node, i, def.ident)).collect() + |(i, def)| ty::ReEarlyBound(def.def_id.node, i, def.ident)).collect() } diff --git a/src/librustc/middle/typeck/variance.rs b/src/librustc/middle/typeck/variance.rs index adb05d252e64c..4e8f0a9468c8d 100644 --- a/src/librustc/middle/typeck/variance.rs +++ b/src/librustc/middle/typeck/variance.rs @@ -613,20 +613,20 @@ impl<'self> ConstraintContext<'self> { region: ty::Region, variance: VarianceTermPtr<'self>) { match region { - ty::re_type_bound(param_id, _, _) => { + ty::ReEarlyBound(param_id, _, _) => { let index = self.inferred_index(param_id); self.add_constraint(index, variance); } - ty::re_static => { } + ty::ReStatic => { } - ty::re_fn_bound(*) => { + ty::ReLateBound(*) => { // We do not infer variance for region parameters on // methods or in fn types. } - ty::re_free(*) | ty::re_scope(*) | ty::re_infer(*) | - ty::re_empty => { + ty::ReFree(*) | ty::ReScope(*) | ty::ReInfer(*) | + ty::ReEmpty => { // We don't expect to see anything but 'static or bound // regions when visiting member types or method types. self.tcx().sess.bug(format!("Unexpected region encountered in \ diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index 89dc71b3af648..c5d7db465e6a1 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -11,11 +11,11 @@ use metadata::encoder; use middle::ty::{ReSkolemized, ReVar}; -use middle::ty::{bound_region, br_anon, br_named}; -use middle::ty::{br_fresh, ctxt, field}; +use middle::ty::{BoundRegion, BrAnon, BrNamed}; +use middle::ty::{BrFresh, ctxt, field}; use middle::ty::{mt, t, param_ty}; -use middle::ty::{re_free, re_scope, re_infer, re_static, Region, - re_empty}; +use middle::ty::{ReFree, ReScope, ReInfer, ReStatic, Region, + ReEmpty}; use middle::ty::{ty_bool, ty_char, ty_bot, ty_box, ty_struct, ty_enum}; use middle::ty::{ty_err, ty_estr, ty_evec, ty_float, ty_bare_fn, ty_closure}; use middle::ty::{ty_nil, ty_opaque_box, ty_opaque_closure_ptr, ty_param}; @@ -71,7 +71,7 @@ pub fn explain_region(cx: ctxt, region: ty::Region) -> ~str { pub fn explain_region_and_span(cx: ctxt, region: ty::Region) -> (~str, Option) { return match region { - re_scope(node_id) => { + ReScope(node_id) => { match cx.items.find(&node_id) { Some(&ast_map::node_block(ref blk)) => { explain_span(cx, "block", blk.span) @@ -104,11 +104,11 @@ pub fn explain_region_and_span(cx: ctxt, region: ty::Region) } } - re_free(ref fr) => { + ReFree(ref fr) => { let prefix = match fr.bound_region { - br_anon(idx) => format!("the anonymous lifetime \\#{} defined on", + BrAnon(idx) => format!("the anonymous lifetime \\#{} defined on", idx + 1), - br_fresh(_) => format!("an anonymous lifetime defined on"), + BrFresh(_) => format!("an anonymous lifetime defined on"), _ => format!("the lifetime {} as defined on", bound_region_ptr_to_str(cx, fr.bound_region)) }; @@ -130,13 +130,13 @@ pub fn explain_region_and_span(cx: ctxt, region: ty::Region) } } - re_static => { (~"the static lifetime", None) } + ReStatic => { (~"the static lifetime", None) } - re_empty => { (~"the empty lifetime", None) } + ReEmpty => { (~"the empty lifetime", None) } // I believe these cases should not occur (except when debugging, // perhaps) - ty::re_infer(_) | ty::re_type_bound(*) | ty::re_fn_bound(*) => { + ty::ReInfer(_) | ty::ReEarlyBound(*) | ty::ReLateBound(*) => { (format!("lifetime {:?}", region), None) } }; @@ -150,13 +150,13 @@ pub fn explain_region_and_span(cx: ctxt, region: ty::Region) } } -pub fn bound_region_ptr_to_str(cx: ctxt, br: bound_region) -> ~str { +pub fn bound_region_ptr_to_str(cx: ctxt, br: BoundRegion) -> ~str { bound_region_to_str(cx, "&", true, br) } pub fn bound_region_to_str(cx: ctxt, prefix: &str, space: bool, - br: bound_region) -> ~str { + br: BoundRegion) -> ~str { let space_str = if space { " " } else { "" }; if cx.sess.verbose() { @@ -164,14 +164,14 @@ pub fn bound_region_to_str(cx: ctxt, } match br { - br_named(_, ident) => format!("{}'{}{}", prefix, + BrNamed(_, ident) => format!("{}'{}{}", prefix, cx.sess.str_of(ident), space_str), - br_anon(_) => prefix.to_str(), - br_fresh(_) => prefix.to_str(), + BrAnon(_) => prefix.to_str(), + BrFresh(_) => prefix.to_str(), } } -pub fn re_scope_id_to_str(cx: ctxt, node_id: ast::NodeId) -> ~str { +pub fn ReScope_id_to_str(cx: ctxt, node_id: ast::NodeId) -> ~str { match cx.items.find(&node_id) { Some(&ast_map::node_block(ref blk)) => { format!("", @@ -204,7 +204,7 @@ pub fn re_scope_id_to_str(cx: ctxt, node_id: ast::NodeId) -> ~str { format!("", node_id) } _ => { cx.sess.bug( - format!("re_scope refers to {}", + format!("ReScope refers to {}", ast_map::node_id_to_str(cx.items, node_id, token::get_ident_interner()))) } } @@ -229,16 +229,16 @@ pub fn region_to_str(cx: ctxt, prefix: &str, space: bool, region: Region) -> ~st // to fit that into a short string. Hence the recommendation to use // `explain_region()` or `note_and_explain_region()`. match region { - ty::re_scope(_) => prefix.to_str(), - ty::re_type_bound(_, _, ident) => cx.sess.str_of(ident).to_owned(), - ty::re_fn_bound(_, br) => bound_region_to_str(cx, prefix, space, br), - ty::re_free(ref fr) => bound_region_to_str(cx, prefix, space, fr.bound_region), - ty::re_infer(ReSkolemized(_, br)) => { + ty::ReScope(_) => prefix.to_str(), + ty::ReEarlyBound(_, _, ident) => cx.sess.str_of(ident).to_owned(), + ty::ReLateBound(_, br) => bound_region_to_str(cx, prefix, space, br), + ty::ReFree(ref fr) => bound_region_to_str(cx, prefix, space, fr.bound_region), + ty::ReInfer(ReSkolemized(_, br)) => { bound_region_to_str(cx, prefix, space, br) } - ty::re_infer(ReVar(_)) => prefix.to_str(), - ty::re_static => format!("{}'static{}", prefix, space_str), - ty::re_empty => format!("{}'{}", prefix, space_str) + ty::ReInfer(ReVar(_)) => prefix.to_str(), + ty::ReStatic => format!("{}'static{}", prefix, space_str), + ty::ReEmpty => format!("{}'{}", prefix, space_str) } } @@ -356,8 +356,8 @@ pub fn ty_to_str(cx: ctxt, typ: t) -> ~str { }; match (cty.sigil, cty.region) { - (ast::ManagedSigil, ty::re_static) | - (ast::OwnedSigil, ty::re_static) => {} + (ast::ManagedSigil, ty::ReStatic) | + (ast::OwnedSigil, ty::ReStatic) => {} (_, region) => { s.push_str(region_to_str(cx, "", true, region)); @@ -689,14 +689,14 @@ impl Repr for ast::Pat { } } -impl Repr for ty::bound_region { +impl Repr for ty::BoundRegion { fn repr(&self, tcx: ctxt) -> ~str { match *self { - ty::br_anon(id) => format!("br_anon({})", id), - ty::br_named(id, ident) => format!("br_named({}, {})", + ty::BrAnon(id) => format!("BrAnon({})", id), + ty::BrNamed(id, ident) => format!("BrNamed({}, {})", id.repr(tcx), ident.repr(tcx)), - ty::br_fresh(id) => format!("br_fresh({})", id), + ty::BrFresh(id) => format!("BrFresh({})", id), } } } @@ -704,41 +704,41 @@ impl Repr for ty::bound_region { impl Repr for ty::Region { fn repr(&self, tcx: ctxt) -> ~str { match *self { - ty::re_type_bound(id, index, ident) => { - format!("re_type_bound({}, {}, {})", + ty::ReEarlyBound(id, index, ident) => { + format!("ReEarlyBound({}, {}, {})", id, index, ident.repr(tcx)) } - ty::re_fn_bound(binder_id, ref bound_region) => { - format!("re_fn_bound({}, {})", + ty::ReLateBound(binder_id, ref bound_region) => { + format!("ReLateBound({}, {})", binder_id, bound_region.repr(tcx)) } - ty::re_free(ref fr) => { - format!("re_free({}, {})", + ty::ReFree(ref fr) => { + format!("ReFree({}, {})", fr.scope_id, fr.bound_region.repr(tcx)) } - ty::re_scope(id) => { - format!("re_scope({})", id) + ty::ReScope(id) => { + format!("ReScope({})", id) } - ty::re_static => { - format!("re_static") + ty::ReStatic => { + format!("ReStatic") } - ty::re_infer(ReVar(ref vid)) => { - format!("re_infer({})", vid.id) + ty::ReInfer(ReVar(ref vid)) => { + format!("ReInfer({})", vid.id) } - ty::re_infer(ReSkolemized(id, ref bound_region)) => { + ty::ReInfer(ReSkolemized(id, ref bound_region)) => { format!("re_skolemized({}, {})", id, bound_region.repr(tcx)) } - ty::re_empty => { - format!("re_empty") + ty::ReEmpty => { + format!("ReEmpty") } } } diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 6245c61dfa184..df9ab083bf25f 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -254,8 +254,8 @@ pub enum Def { #[deriving(Clone, Eq, IterBytes, Encodable, Decodable, ToStr)] pub enum DefRegion { DefStaticRegion, - DefTypeBoundRegion(/* index */ uint, /* lifetime decl */ NodeId), - DefFnBoundRegion(/* binder_id */ NodeId, /* depth */ uint, /* lifetime decl */ NodeId), + DefEarlyBoundRegion(/* index */ uint, /* lifetime decl */ NodeId), + DefLateBoundRegion(/* binder_id */ NodeId, /* depth */ uint, /* lifetime decl */ NodeId), DefFreeRegion(/* block scope */ NodeId, /* lifetime decl */ NodeId), } From bc3e84250868dff44ce0ea0919d9db8549dddf32 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 29 Oct 2013 11:19:28 -0400 Subject: [PATCH 09/16] Update FIXMEs with issue numbers --- src/librustc/middle/typeck/check/mod.rs | 4 +--- src/librustc/middle/typeck/check/regionmanip.rs | 12 +++--------- src/librustc/middle/typeck/collect.rs | 7 ++++--- src/libsyntax/print/pprust.rs | 2 +- 4 files changed, 9 insertions(+), 16 deletions(-) diff --git a/src/librustc/middle/typeck/check/mod.rs b/src/librustc/middle/typeck/check/mod.rs index ebe3c828262c2..95b811f6765cf 100644 --- a/src/librustc/middle/typeck/check/mod.rs +++ b/src/librustc/middle/typeck/check/mod.rs @@ -583,9 +583,7 @@ pub fn check_item(ccx: @mut CrateCtxt, it: @ast::item) { ast::item_fn(ref decl, _, _, _, ref body) => { let fn_tpt = ty::lookup_item_type(ccx.tcx, ast_util::local_def(it.id)); - // FIXME -- this won't fly for the case where people reference - // a lifetime from within a type parameter. That's actually fairly - // tricky. + // FIXME(#5121) -- won't work for lifetimes that appear in type bounds let param_env = ty::construct_parameter_environment( ccx.tcx, None, diff --git a/src/librustc/middle/typeck/check/regionmanip.rs b/src/librustc/middle/typeck/check/regionmanip.rs index a73aa46fbec2b..ec11adbfa3dab 100644 --- a/src/librustc/middle/typeck/check/regionmanip.rs +++ b/src/librustc/middle/typeck/check/regionmanip.rs @@ -94,15 +94,9 @@ pub fn relate_nested_regions( relate_op: &'self fn(ty::Region, ty::Region), } - // FIXME we should define more precisely when a - // region is considered "nested" and take variance into account. - // - // I can't decide whether skipping closure parameter types and - // so on is necessary or not. What is the difference, after all, - // between `&'a |&'b T|` and `&'a Fn<&'b T>`? And yet in the - // latter case I'm inclined to think we should probably track - // the relationship (but then again maybe we should just skip - // all such cases until it "proves necessary") + // FIXME(#10151) -- Define more precisely when a region is + // considered "nested". Consider taking variance into account as + // well. impl<'self> TypeFolder for RegionRelator<'self> { fn tcx(&self) -> ty::ctxt { diff --git a/src/librustc/middle/typeck/collect.rs b/src/librustc/middle/typeck/collect.rs index e55005d62e912..2a55a681290e0 100644 --- a/src/librustc/middle/typeck/collect.rs +++ b/src/librustc/middle/typeck/collect.rs @@ -359,7 +359,7 @@ pub fn ensure_trait_methods(ccx: &CrateCtxt, let num_trait_type_params = trait_generics.type_param_defs.len(); ty::Method::new( *m_ident, - // FIXME -- what about lifetime parameters here? + // FIXME(#5121) -- distinguish early vs late lifetime params ty_generics(this, m_generics, num_trait_type_params), transformed_self_ty, fty, @@ -486,7 +486,7 @@ fn convert_methods(ccx: &CrateCtxt, let num_rcvr_type_params = rcvr_generics.ty_params.len(); ty::Method::new( m.ident, - // FIXME region param + // FIXME(#5121) -- distinguish early vs late lifetime params ty_generics(ccx, &m.generics, num_rcvr_type_params), transformed_self_ty, fty, @@ -683,7 +683,8 @@ pub fn instantiate_trait_ref(ccx: &CrateCtxt, * trait. Fails if the type is a type other than an trait type. */ - let rscope = ExplicitRscope; // FIXME + // FIXME(#5121) -- distinguish early vs late lifetime params + let rscope = ExplicitRscope; match lookup_def_tcx(ccx.tcx, ast_trait_ref.path.span, ast_trait_ref.ref_id) { ast::DefTrait(trait_did) => { diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index fd02ac68f4e1a..7b02d036511aa 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -1905,7 +1905,7 @@ pub fn print_meta_item(s: @ps, item: &ast::MetaItem) { pub fn print_view_path(s: @ps, vp: &ast::view_path) { match vp.node { ast::view_path_simple(ident, ref path, _) => { - // FIXME can't compare identifiers directly here + // FIXME(#6993) can't compare identifiers directly here if path.segments.last().identifier.name != ident.name { print_ident(s, ident); space(s.s); From f36a891fe22f656454b70b8f2aa64bef9133e7f0 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 8 Nov 2013 15:52:36 -0500 Subject: [PATCH 10/16] Address comments from @pnkfelix (thanks for the detailed review) --- src/librustc/middle/ty.rs | 8 +- src/librustc/middle/typeck/astconv.rs | 17 +- src/librustc/middle/typeck/check/mod.rs | 5 +- src/librustc/middle/typeck/collect.rs | 22 +- src/librustc/middle/typeck/rscope.rs | 24 ++- src/librustc/middle/typeck/variance.rs | 193 ++++++++++++++++-- src/libsyntax/ast.rs | 6 - ...ns-variance-contravariant-use-covariant.rs | 37 ++++ ...ns-variance-covariant-use-contravariant.rs | 23 +-- ...ns-variance-invariant-use-contravariant.rs | 18 +- ...egions-variance-invariant-use-covariant.rs | 9 +- 11 files changed, 282 insertions(+), 80 deletions(-) create mode 100644 src/test/compile-fail/regions-variance-contravariant-use-covariant.rs diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index 390c651ea7977..ecb178e2c97c8 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -218,10 +218,10 @@ pub struct ItemVariances { #[deriving(Clone, Eq, Decodable, Encodable)] pub enum Variance { - Covariant, - Invariant, - Contravariant, - Bivariant, + Covariant, // T <: T iff A <: B -- e.g., function return type + Invariant, // T <: T iff B == A -- e.g., type of mutable cell + Contravariant, // T <: T iff B <: A -- e.g., function param type + Bivariant, // T <: T -- e.g., unused type parameter } #[deriving(Decodable, Encodable)] diff --git a/src/librustc/middle/typeck/astconv.rs b/src/librustc/middle/typeck/astconv.rs index 5040c19158e0b..57581306b5d5d 100644 --- a/src/librustc/middle/typeck/astconv.rs +++ b/src/librustc/middle/typeck/astconv.rs @@ -116,7 +116,7 @@ pub fn ast_region_to_region( r } -pub fn opt_ast_region_to_region( +fn opt_ast_region_to_region( this: &AC, rscope: &RS, default_span: Span, @@ -129,14 +129,14 @@ pub fn opt_ast_region_to_region( None => { match rscope.anon_regions(default_span, 1) { - None => { + Err(()) => { debug!("optional region in illegal location"); this.tcx().sess.span_err( default_span, "missing lifetime specifier"); ty::ReStatic } - Some(rs) => { + Ok(rs) => { rs[0] } } @@ -178,7 +178,7 @@ fn ast_path_substs( let anon_regions = rscope.anon_regions(path.span, expected_num_region_params); - if supplied_num_region_params != 0 || anon_regions.is_none() { + if supplied_num_region_params != 0 || anon_regions.is_err() { tcx.sess.span_err( path.span, format!("wrong number of lifetime parameters: \ @@ -188,9 +188,9 @@ fn ast_path_substs( } match anon_regions { - Some(v) => opt_vec::from(v), - None => opt_vec::from(vec::from_fn(expected_num_region_params, - |_| ty::ReStatic)) // hokey + Ok(v) => opt_vec::from(v), + Err(()) => opt_vec::from(vec::from_fn(expected_num_region_params, + |_| ty::ReStatic)) // hokey } }; @@ -277,8 +277,7 @@ pub static NO_REGIONS: uint = 1; pub static NO_TPS: uint = 2; // Parses the programmer's textual representation of a type into our -// internal notion of a type. `getter` is a function that returns the type -// corresponding to a definition ID: +// internal notion of a type. pub fn ast_ty_to_ty( this: &AC, rscope: &RS, ast_ty: &ast::Ty) -> ty::t { diff --git a/src/librustc/middle/typeck/check/mod.rs b/src/librustc/middle/typeck/check/mod.rs index 95b811f6765cf..98d154a8d73b6 100644 --- a/src/librustc/middle/typeck/check/mod.rs +++ b/src/librustc/middle/typeck/check/mod.rs @@ -800,7 +800,6 @@ fn check_impl_methods_against_trait(ccx: @mut CrateCtxt, * - impl_m_body_id: id of the method body * - trait_m: the method in the trait * - trait_substs: the substitutions used on the type of the trait - * - self_ty: the self type of the impl */ pub fn compare_impl_method(tcx: ty::ctxt, impl_generics: &ty::Generics, @@ -1062,8 +1061,8 @@ impl FnCtxt { impl RegionScope for @mut infer::InferCtxt { fn anon_regions(&self, span: Span, - count: uint) -> Option<~[ty::Region]> { - Some(vec::from_fn( + count: uint) -> Result<~[ty::Region], ()> { + Ok(vec::from_fn( count, |_| self.next_region_var(infer::MiscVariable(span)))) } diff --git a/src/librustc/middle/typeck/collect.rs b/src/librustc/middle/typeck/collect.rs index 2a55a681290e0..36ed9f94fb71a 100644 --- a/src/librustc/middle/typeck/collect.rs +++ b/src/librustc/middle/typeck/collect.rs @@ -517,17 +517,17 @@ pub fn convert(ccx: &CrateCtxt, it: &ast::item) { let tcx = ccx.tcx; debug!("convert: item {} with id {}", tcx.sess.str_of(it.ident), it.id); match it.node { - // These don't define types. - ast::item_foreign_mod(_) | ast::item_mod(_) => {} - ast::item_enum(ref enum_definition, ref generics) => { - ensure_no_ty_param_bounds(ccx, it.span, generics, "enumeration"); - let tpt = ty_of_item(ccx, it); - write_ty_to_tcx(tcx, it.id, tpt.ty); - get_enum_variant_types(ccx, - tpt.ty, - enum_definition.variants, - generics); - } + // These don't define types. + ast::item_foreign_mod(_) | ast::item_mod(_) => {} + ast::item_enum(ref enum_definition, ref generics) => { + ensure_no_ty_param_bounds(ccx, it.span, generics, "enumeration"); + let tpt = ty_of_item(ccx, it); + write_ty_to_tcx(tcx, it.id, tpt.ty); + get_enum_variant_types(ccx, + tpt.ty, + enum_definition.variants, + generics); + } ast::item_impl(ref generics, ref opt_trait_ref, ref selfty, ref ms) => { let i_ty_generics = ty_generics(ccx, generics, 0); let selfty = ccx.to_ty(&ExplicitRscope, selfty); diff --git a/src/librustc/middle/typeck/rscope.rs b/src/librustc/middle/typeck/rscope.rs index 3d095d1e8a5e8..9a32eafa8e4de 100644 --- a/src/librustc/middle/typeck/rscope.rs +++ b/src/librustc/middle/typeck/rscope.rs @@ -16,11 +16,21 @@ use syntax::ast; use syntax::codemap::Span; use syntax::opt_vec::OptVec; +/// Defines strategies for handling regions that are omitted. For +/// example, if one writes the type `&Foo`, then the lifetime of of +/// this borrowed pointer has been omitted. When converting this +/// type, the generic functions in astconv will invoke `anon_regions` +/// on the provided region-scope to decide how to translate this +/// omitted region. +/// +/// It is not always legal to omit regions, therefore `anon_regions` +/// can return `Err(())` to indicate that this is not a scope in which +/// regions can legally be omitted. pub trait RegionScope { fn anon_regions(&self, span: Span, count: uint) - -> Option<~[ty::Region]>; + -> Result<~[ty::Region], ()>; } // A scope in which all regions must be explicitly named @@ -30,11 +40,13 @@ impl RegionScope for ExplicitRscope { fn anon_regions(&self, _span: Span, _count: uint) - -> Option<~[ty::Region]> { - None + -> Result<~[ty::Region], ()> { + Err(()) } } +/// A scope in which we generate anonymous, late-bound regions for +/// omitted regions. This occurs in function signatures. pub struct BindingRscope { binder_id: ast::NodeId, anon_bindings: @mut uint @@ -53,11 +65,11 @@ impl RegionScope for BindingRscope { fn anon_regions(&self, _: Span, count: uint) - -> Option<~[ty::Region]> { + -> Result<~[ty::Region], ()> { let idx = *self.anon_bindings; *self.anon_bindings += count; - Some(vec::from_fn(count, |i| ty::ReLateBound(self.binder_id, - ty::BrAnon(idx + i)))) + Ok(vec::from_fn(count, |i| ty::ReLateBound(self.binder_id, + ty::BrAnon(idx + i)))) } } diff --git a/src/librustc/middle/typeck/variance.rs b/src/librustc/middle/typeck/variance.rs index 4e8f0a9468c8d..1b435d11404b1 100644 --- a/src/librustc/middle/typeck/variance.rs +++ b/src/librustc/middle/typeck/variance.rs @@ -1,4 +1,4 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// Copyright 2013 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // @@ -15,13 +15,137 @@ algorithm is taken from Section 4 of the paper "Taming the Wildcards: Combining Definition- and Use-Site Variance" published in PLDI'11 and written by Altidor et al., and hereafter referred to as The Paper. +This inference is explicitly designed *not* to consider the uses of +types within code. To determine the variance of type parameters +defined on type `X`, we only consider the definition of the type `X` +and the definitions of any types it references. + +We only infer variance for type parameters found on *types*: structs, +enums, and traits. We do not infer variance for type parameters found +on fns or impls. This is because those things are not type definitions +and variance doesn't really make sense in that context. + +It is worth covering what variance means in each case. For structs and +enums, I think it is fairly straightforward. The variance of the type +or lifetime parameters defines whether `T` is a subtype of `T` +(resp. `T<'a>` and `T<'b>`) based on the relationship of `A` and `B` +(resp. `'a` and `'b`). (FIXME #3598 -- we do not currently make use of +the variances we compute for type parameters.) + +### Variance on traits + +The meaning of variance for trait parameters is more subtle and worth +expanding upon. There are in fact two uses of the variance values we +compute. + +#### Trait variance and object types + +The first is for object types. Just as with structs and enums, we can +decide the subtyping relationship between two object types `&Trait` +and `&Trait` based on the relationship of `A` and `B`. Note that +for object types we ignore the `Self` type parameter -- it is unknown, +and the nature of dynamic dispatch ensures that we will always call a +function that is expected the appropriate `Self` type. However, we +must be careful with the other type parameters, or else we could end +up calling a function that is expecting one type but provided another. + +To see what I mean, consider a trait like so: + + trait ConvertTo { + fn convertTo(&self) -> A; + } + +Intuitively, If we had one object `O=&ConvertTo` and another +`S=&ConvertTo`, then `S <: O` because `String <: Object` +(presuming Java-like "string" and "object" types, my go to examples +for subtyping). The actual algorithm would be to compare the +(explicit) type parameters pairwise respecting their variance: here, +the type parameter A is covariant (it appears only in a return +position), and hence we require that `String <: Object`. + +You'll note though that we did not consider the binding for the +(implicit) `Self` type parameter: in fact, it is unknown, so that's +good. The reason we can ignore that parameter is precisely because we +don't need to know its value until a call occurs, and at that time (as +you said) the dynamic nature of virtual dispatch means the code we run +will be correct for whatever value `Self` happens to be bound to for +the particular object whose method we called. `Self` is thus different +from `A`, because the caller requires that `A` be known in order to +know the return type of the method `convertTo()`. (As an aside, we +have rules preventing methods where `Self` appears outside of the +receiver position from being called via an object.) + +#### Trait variance and vtable resolution + +But traits aren't only used with objects. They're also used when +deciding whether a given impl satisfies a given trait bound (or should +be -- FIXME #5781). To set the scene here, imagine I had a function: + + fn convertAll>(v: &[T]) { + ... + } + +Now imagine that I have an implementation of `ConvertTo` for `Object`: + + impl ConvertTo for Object { ... } + +And I want to call `convertAll` on an array of strings. Suppose +further that for whatever reason I specifically supply the value of +`String` for the type parameter `T`: + + let mut vector = ~["string", ...]; + convertAll::(v); + +Is this legal? To put another way, can we apply the `impl` for +`Object` to the type `String`? The answer is yes, but to see why +we have to expand out what will happen: + +- `convertAll` will create a pointer to one of the entries in the + vector, which will have type `&String` +- It will then call the impl of `convertTo()` that is intended + for use with objects. This has the type: + + fn(self: &Object) -> int + + It is ok to provide a value for `self` of type `&String` because + `&String <: &Object`. + +OK, so intuitively we want this to be legal, so let's bring this back +to variance and see whether we are computing the correct result. We +must first figure out how to phrase the question "is an impl for +`Object,int` usable where an impl for `String,int` is expected?" + +Maybe it's helpful to think of a dictionary-passing implementation of +type classes. In that case, `convertAll()` takes an implicit parameter +representing the impl. In short, we *have* an impl of type: + + V_O = ConvertTo for Object + +and the function prototype expects an impl of type: + + V_S = ConvertTo for String + +As with any argument, this is legal if the type of the value given +(`V_O`) is a subtype of the type expected (`V_S`). So is `V_O <: V_S`? +The answer will depend on the variance of the various parameters. In +this case, because the `Self` parameter is contravariant and `A` is +covariant, it means that: + + V_O <: V_S iff + int <: int + String <: Object + +These conditions are satisfied and so we are happy. + +### The algorithm + The basic idea is quite straightforward. We iterate over the types defined and, for each use of a type parameter X, accumulate a constraint indicating that the variance of X must be valid for the variance of that use site. We then iteratively refine the variance of X until all constraints are met. There is *always* a sol'n, because at the limit we can declare all type parameters to be invariant and all -constriants will be satisfied. +constraints will be satisfied. As a simple example, consider: @@ -46,8 +170,8 @@ results are based on a variance lattice defined as follows: o Bottom (invariant) Based on this lattice, the solution V(A)=+, V(B)=-, V(C)=o is the -minimal solution (which is what we are looking for; the maximal -solution is just that all variables are invariant. Not so exciting.). +optimal solution. Note that there is always a naive solution which +just declares all variables to be invariant. You may be wondering why fixed-point iteration is required. The reason is that the variance of a use site may itself be a function of the @@ -59,9 +183,12 @@ take the form: Here the notation V(X) indicates the variance of a type/region parameter `X` with respect to its defining class. `Term x Term` -represents the "variance transform" as defined in the paper -- `V1 x -V2` is the resulting variance when a use site with variance V2 appears -inside a use site with variance V1. +represents the "variance transform" as defined in the paper: + + If the variance of a type variable `X` in type expression `E` is `V2` + and the definition-site variance of the [corresponding] type parameter + of a class `C` is `V1`, then the variance of `X` in the type expression + `C` is `V3 = V1.xform(V2)`. */ @@ -128,9 +255,13 @@ struct TermsContext<'self> { tcx: ty::ctxt, arena: &'self Arena, + empty_variances: @ty::ItemVariances, + // Maps from the node id of a type/generic parameter to the // corresponding inferred index. inferred_map: HashMap, + + // Maps from an InferredIndex to the info for that variable. inferred_infos: ~[InferredInfo<'self>], } @@ -153,6 +284,12 @@ fn determine_parameters_to_be_inferred<'a>(tcx: ty::ctxt, arena: arena, inferred_map: HashMap::new(), inferred_infos: ~[], + + // cache and share the variance struct used for items with + // no type/region parameters + empty_variances: @ty::ItemVariances { self_param: None, + type_params: opt_vec::Empty, + region_params: opt_vec::Empty } }; visit::walk_crate(&mut terms_cx, crate, ()); @@ -228,11 +365,7 @@ impl<'self> Visitor<()> for TermsContext<'self> { if self.num_inferred() == inferreds_on_entry { let newly_added = self.tcx.item_variance_map.insert( ast_util::local_def(item.id), - @ty::ItemVariances { - self_param: None, - type_params: opt_vec::Empty, - region_params: opt_vec::Empty - }); + self.empty_variances); assert!(newly_added); } @@ -262,6 +395,7 @@ impl<'self> Visitor<()> for TermsContext<'self> { struct ConstraintContext<'self> { terms_cx: TermsContext<'self>, + // These are pointers to common `ConstantTerm` instances covariant: VarianceTermPtr<'self>, contravariant: VarianceTermPtr<'self>, invariant: VarianceTermPtr<'self>, @@ -309,7 +443,7 @@ impl<'self> Visitor<()> for ConstraintContext<'self> { // annoyingly takes it upon itself to run off and // evaluate the discriminants eagerly (*grumpy* that's // not the typical pattern). This results in double - // error messagees because typeck goes off and does + // error messages because typeck goes off and does // this at a later time. All we really care about is // the types of the variant arguments, so we just call // `ty::VariantInfo::from_ast_variant()` ourselves @@ -340,8 +474,14 @@ impl<'self> Visitor<()> for ConstraintContext<'self> { for method in methods.iter() { match method.transformed_self_ty { Some(self_ty) => { - // The self type is a parameter, so its type - // should be considered contravariant: + // The implicit self parameter is basically + // equivalent to a normal parameter declared + // like: + // + // self : self_ty + // + // where self_ty is `&Self` or `&mut Self` + // or whatever. self.add_constraints_from_ty( self_ty, self.contravariant); } @@ -465,6 +605,8 @@ impl<'self> ConstraintContext<'self> { } } + /// Adds constraints appropriate for an instance of `ty` appearing + /// in a context with ambient variance `variance` fn add_constraints_from_ty(&mut self, ty: ty::t, variance: VarianceTermPtr<'self>) { @@ -558,6 +700,8 @@ impl<'self> ConstraintContext<'self> { } } + /// Adds constraints appropriate for a vector with vstore `vstore` + /// appearing in a context with ambient variance `variance` fn add_constraints_from_vstore(&mut self, vstore: ty::vstore, variance: VarianceTermPtr<'self>) { @@ -572,6 +716,8 @@ impl<'self> ConstraintContext<'self> { } } + /// Adds constraints appropriate for a nominal type (enum, struct, + /// object, etc) appearing in a context with ambient variance `variance` fn add_constraints_from_substs(&mut self, def_id: ast::DefId, generics: &ty::Generics, @@ -599,6 +745,8 @@ impl<'self> ConstraintContext<'self> { } } + /// Adds constraints appropriate for a function with signature + /// `sig` appearing in a context with ambient variance `variance` fn add_constraints_from_sig(&mut self, sig: &ty::FnSig, variance: VarianceTermPtr<'self>) { @@ -609,6 +757,8 @@ impl<'self> ConstraintContext<'self> { self.add_constraints_from_ty(sig.output, variance); } + /// Adds constraints appropriate for a region appearing in a + /// context with ambient variance `variance` fn add_constraints_from_region(&mut self, region: ty::Region, variance: VarianceTermPtr<'self>) { @@ -636,6 +786,8 @@ impl<'self> ConstraintContext<'self> { } } + /// Adds constraints appropriate for a mutability-type pair + /// appearing in a context with ambient variance `variance` fn add_constraints_from_mt(&mut self, mt: &ty::mt, variance: VarianceTermPtr<'self>) { @@ -657,13 +809,15 @@ impl<'self> ConstraintContext<'self> { * * The final phase iterates over the constraints, refining the variance * for each inferred until a fixed point is reached. This will be the - * maximal solution to the constraints. The final variance for each + * optimal solution to the constraints. The final variance for each * inferred is then written into the `variance_map` in the tcx. */ struct SolveContext<'self> { terms_cx: TermsContext<'self>, constraints: ~[Constraint<'self>], + + // Maps from an InferredIndex to the inferred value for that variable. solutions: ~[ty::Variance] } @@ -715,7 +869,12 @@ impl<'self> SolveContext<'self> { // Collect all the variances for a particular item and stick // them into the variance map. We rely on the fact that we // generate all the inferreds for a particular item - // consecutively. + // consecutively (that is, we collect solutions for an item + // until we see a new item id, and we assume (1) the solutions + // are in the same order as the type parameters were declared + // and (2) all solutions or a given item appear before a new + // item id). + let tcx = self.terms_cx.tcx; let item_variance_map = tcx.item_variance_map; let solutions = &self.solutions; diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index df9ab083bf25f..88a8bbf7cf28f 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -259,12 +259,6 @@ pub enum DefRegion { DefFreeRegion(/* block scope */ NodeId, /* lifetime decl */ NodeId), } -#[deriving(Clone, Eq, IterBytes, Encodable, Decodable, ToStr)] -pub struct DefNamedRegion { - node_id: NodeId, - depth: uint, -} - // The set of MetaItems that define the compilation environment of the crate, // used to drive conditional compilation pub type CrateConfig = ~[@MetaItem]; diff --git a/src/test/compile-fail/regions-variance-contravariant-use-covariant.rs b/src/test/compile-fail/regions-variance-contravariant-use-covariant.rs new file mode 100644 index 0000000000000..5ac4afb6bfce1 --- /dev/null +++ b/src/test/compile-fail/regions-variance-contravariant-use-covariant.rs @@ -0,0 +1,37 @@ +// Copyright 2012 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. + +// Test that a type which is covariant with respect to its region +// parameter yields an error when used in a contravariant way. +// +// Note: see variance-regions-*.rs for the tests that check that the +// variance inference works in the first place. + +// This is covariant with respect to 'a, meaning that +// Covariant<'foo> <: Covariant<'static> because +// 'foo <= 'static +struct Contravariant<'a> { + f: &'a int +} + +fn use_<'short,'long>(c: Contravariant<'short>, + s: &'short int, + l: &'long int, + _where:Option<&'short &'long ()>) { + + // Test whether Contravariant<'short> <: Contravariant<'long>. Since + // 'short <= 'long, this would be true if the Contravariant type were + // covariant with respect to its parameter 'a. + + let _: Contravariant<'long> = c; //~ ERROR mismatched types + //~^ ERROR cannot infer an appropriate lifetime +} + +fn main() {} diff --git a/src/test/compile-fail/regions-variance-covariant-use-contravariant.rs b/src/test/compile-fail/regions-variance-covariant-use-contravariant.rs index b004bc471a56d..5cc3f1bdc3780 100644 --- a/src/test/compile-fail/regions-variance-covariant-use-contravariant.rs +++ b/src/test/compile-fail/regions-variance-covariant-use-contravariant.rs @@ -8,8 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// Test that a type which is contravariant with respect to its region -// parameter yields an error when used in a covariant way. +// Test that a type which is covariant with respect to its region +// parameter yields an error when used in a contravariant way. // // Note: see variance-regions-*.rs for the tests that check that the // variance inference works in the first place. @@ -21,18 +21,17 @@ struct Covariant<'a> { f: extern "Rust" fn(&'a int) } -fn use_<'a>(c: Covariant<'a>) { - let x = 3; +fn use_<'short,'long>(c: Covariant<'long>, + s: &'short int, + l: &'long int, + _where:Option<&'short &'long ()>) { - // 'b winds up being inferred to 'a because - // Covariant<'a> <: Covariant<'b> => 'a <= 'b - // - // Borrow checker then reports an error because `x` does not - // have the lifetime 'a. - collapse(&x, c); //~ ERROR borrowed value does not live long enough + // Test whether Covariant<'long> <: Covariant<'short>. Since + // 'short <= 'long, this would be true if the Covariant type were + // contravariant with respect to its parameter 'a. - - fn collapse<'b>(x: &'b int, c: Covariant<'b>) { } + let _: Covariant<'short> = c; //~ ERROR mismatched types + //~^ ERROR cannot infer an appropriate lifetime } fn main() {} diff --git a/src/test/compile-fail/regions-variance-invariant-use-contravariant.rs b/src/test/compile-fail/regions-variance-invariant-use-contravariant.rs index b105fc72692d2..2180964083250 100644 --- a/src/test/compile-fail/regions-variance-invariant-use-contravariant.rs +++ b/src/test/compile-fail/regions-variance-invariant-use-contravariant.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// Test that a covariant region parameter used in a covariant position +// Test that an invariant region parameter used in a contravariant way // yields an error. // // Note: see variance-regions-*.rs for the tests that check that the @@ -18,16 +18,16 @@ struct Invariant<'a> { f: &'static mut &'a int } -fn use_<'a>(c: Invariant<'a>) { - let x = 3; +fn use_<'short,'long>(c: Invariant<'long>, + s: &'short int, + l: &'long int, + _where:Option<&'short &'long ()>) { - // 'b winds up being inferred to 'a, because that is the - // only way that Invariant<'a> <: Invariant<'b>, and hence - // we get an error in the borrow checker because &x cannot - // live that long - collapse(&x, c); //~ ERROR borrowed value does not live long enough + // Test whether Invariant<'long> <: Invariant<'short>. Since + // 'short <= 'long, this would be true if the Invariant type were + // contravariant with respect to its parameter 'a. - fn collapse<'b>(x: &'b int, c: Invariant<'b>) { } + let _: Invariant<'short> = c; //~ ERROR lifetime mistach } fn main() { } diff --git a/src/test/compile-fail/regions-variance-invariant-use-covariant.rs b/src/test/compile-fail/regions-variance-invariant-use-covariant.rs index 9aae0f87f5bec..9cdd05f8ebe18 100644 --- a/src/test/compile-fail/regions-variance-invariant-use-covariant.rs +++ b/src/test/compile-fail/regions-variance-invariant-use-covariant.rs @@ -18,9 +18,12 @@ struct Invariant<'a> { f: &'static mut &'a int } -fn use_<'a>(c: Invariant<'a>) { - // For this assignment to be legal, Invariant<'a> <: Invariant<'static>, - // which (if Invariant were covariant) would require 'a <= 'static. +fn use_<'b>(c: Invariant<'b>) { + + // For this assignment to be legal, Invariant<'b> <: Invariant<'static>. + // Since 'b <= 'static, this would be true if Invariant were covariant + // with respect to its parameter 'a. + let _: Invariant<'static> = c; //~ ERROR mismatched types } From f4f4a35b5b1fe54b05b2dac3428c55ef2d3923b1 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 8 Nov 2013 16:19:28 -0500 Subject: [PATCH 11/16] Add new tests showing multiple lifetime parameters in use --- ...ariant-use-covariant-in-second-position.rs | 39 ++++++ ...ns-variance-contravariant-use-covariant.rs | 4 +- src/test/run-pass/regions-mock-tcx.rs | 124 ++++++++++++++++++ 3 files changed, 165 insertions(+), 2 deletions(-) create mode 100644 src/test/compile-fail/regions-variance-contravariant-use-covariant-in-second-position.rs create mode 100644 src/test/run-pass/regions-mock-tcx.rs diff --git a/src/test/compile-fail/regions-variance-contravariant-use-covariant-in-second-position.rs b/src/test/compile-fail/regions-variance-contravariant-use-covariant-in-second-position.rs new file mode 100644 index 0000000000000..77a54fec7bf7c --- /dev/null +++ b/src/test/compile-fail/regions-variance-contravariant-use-covariant-in-second-position.rs @@ -0,0 +1,39 @@ +// Copyright 2012 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. + +// Test that a type which is covariant with respect to its region +// parameter yields an error when used in a contravariant way. +// +// Note: see variance-regions-*.rs for the tests that check that the +// variance inference works in the first place. + +// `S` is contravariant with respect to both parameters. +struct S<'a, 'b> { + f: &'a int, + g: &'b int, +} + +fn use_<'short,'long>(c: S<'long, 'short>, + s: &'short int, + l: &'long int, + _where:Option<&'short &'long ()>) { + + let _: S<'long, 'short> = c; // OK + let _: S<'short, 'short> = c; // OK + + // Test whether S<_,'short> <: S<_,'long>. Since + // 'short <= 'long, this would be true if the Contravariant type were + // covariant with respect to its parameter 'a. + + let _: S<'long, 'long> = c; //~ ERROR mismatched types + //~^ ERROR cannot infer an appropriate lifetime +} + +fn main() {} diff --git a/src/test/compile-fail/regions-variance-contravariant-use-covariant.rs b/src/test/compile-fail/regions-variance-contravariant-use-covariant.rs index 5ac4afb6bfce1..3f0161d9deb2b 100644 --- a/src/test/compile-fail/regions-variance-contravariant-use-covariant.rs +++ b/src/test/compile-fail/regions-variance-contravariant-use-covariant.rs @@ -14,8 +14,8 @@ // Note: see variance-regions-*.rs for the tests that check that the // variance inference works in the first place. -// This is covariant with respect to 'a, meaning that -// Covariant<'foo> <: Covariant<'static> because +// This is contravariant with respect to 'a, meaning that +// Contravariant<'foo> <: Contravariant<'static> because // 'foo <= 'static struct Contravariant<'a> { f: &'a int diff --git a/src/test/run-pass/regions-mock-tcx.rs b/src/test/run-pass/regions-mock-tcx.rs new file mode 100644 index 0000000000000..f98e475094cac --- /dev/null +++ b/src/test/run-pass/regions-mock-tcx.rs @@ -0,0 +1,124 @@ +// Copyright 2012 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. + +// Test a sample usage pattern for regions. Makes use of the +// following features: +// +// - Multiple lifetime parameters +// - Arenas + +extern mod extra; + +use extra::arena; +use extra::arena::Arena; +use std::hashmap::HashMap; +use std::cast; +use std::libc; +use std::mem; + +type Type<'tcx> = &'tcx TypeStructure<'tcx>; + +#[deriving(Eq)] +enum TypeStructure<'tcx> { + TypeInt, + TypeFunction(Type<'tcx>, Type<'tcx>), +} + +struct TypeContext<'tcx, 'ast> { + ty_arena: &'tcx Arena, + types: ~[Type<'tcx>], + type_table: HashMap>, + + ast_arena: &'ast Arena, + ast_counter: uint, +} + +impl<'tcx,'ast> TypeContext<'tcx, 'ast> { + fn new(ty_arena: &'tcx Arena, ast_arena: &'ast Arena) + -> TypeContext<'tcx, 'ast> { + TypeContext { ty_arena: ty_arena, + types: ~[], + type_table: HashMap::new(), + + ast_arena: ast_arena, + ast_counter: 0 } + } + + fn add_type(&mut self, s: TypeStructure<'tcx>) -> Type<'tcx> { + for &ty in self.types.iter() { + if *ty == s { + return ty; + } + } + + let ty = self.ty_arena.alloc(|| s); + self.types.push(ty); + ty + } + + fn set_type(&mut self, id: NodeId, ty: Type<'tcx>) -> Type<'tcx> { + self.type_table.insert(id, ty); + ty + } + + fn ast(&mut self, a: AstKind<'ast>) -> Ast<'ast> { + let id = self.ast_counter; + self.ast_counter += 1; + self.ast_arena.alloc(|| AstStructure { id: NodeId {id:id}, kind: a }) + } +} + +#[deriving(Eq, IterBytes)] +struct NodeId { + id: uint +} + +type Ast<'ast> = &'ast AstStructure<'ast>; + +struct AstStructure<'ast> { + id: NodeId, + kind: AstKind<'ast> +} + +enum AstKind<'ast> { + ExprInt, + ExprVar(uint), + ExprLambda(Ast<'ast>), + // ... +} + +fn compute_types<'tcx,'ast>(tcx: &mut TypeContext<'tcx,'ast>, + ast: Ast<'ast>) -> Type<'tcx> +{ + match ast.kind { + ExprInt | ExprVar(_) => { + let ty = tcx.add_type(TypeInt); + tcx.set_type(ast.id, ty) + } + + ExprLambda(ast) => { + let arg_ty = tcx.add_type(TypeInt); + let body_ty = compute_types(tcx, ast); + let lambda_ty = tcx.add_type(TypeFunction(arg_ty, body_ty)); + tcx.set_type(ast.id, lambda_ty) + } + + // ... + } +} + +pub fn main() { + let ty_arena = arena::Arena::new(); + let ast_arena = arena::Arena::new(); + let mut tcx = TypeContext::new(&ty_arena, &ast_arena); + let ast = tcx.ast(ExprInt); + let ty = compute_types(&mut tcx, ast); + assert_eq!(*ty, TypeInt); +} From 98f79735c3f76c9e1a263a4a37104bda51c5dd5f Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 8 Nov 2013 20:59:43 -0500 Subject: [PATCH 12/16] Merge failures --- src/librustc/metadata/tydecode.rs | 1 + src/librustc/middle/ty.rs | 5 +++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/librustc/metadata/tydecode.rs b/src/librustc/metadata/tydecode.rs index 18447e6cbc8cd..31561e730d541 100644 --- a/src/librustc/metadata/tydecode.rs +++ b/src/librustc/metadata/tydecode.rs @@ -551,6 +551,7 @@ fn parse_sig(st: &mut PState, conv: conv_did) -> ty::FnSig { let variadic = match next(st) { 'V' => true, 'N' => false, + r => fail!(format!("Bad variadic: {}", r)), }; let ret_ty = parse_ty(st, |x,y| conv(x,y)); ty::FnSig {binder_id: id, diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index ecb178e2c97c8..5072a95ddcf1b 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -4245,7 +4245,8 @@ pub fn normalize_ty(cx: ctxt, t: t) -> t { // are erased at trans time. ty::FnSig { binder_id: ast::DUMMY_NODE_ID, inputs: ty_fold::fold_ty_vec(self, sig.inputs), - output: self.fold_ty(sig.output) } + output: self.fold_ty(sig.output), + variadic: sig.variadic } } } } @@ -4572,7 +4573,7 @@ pub fn hash_crate_independent(tcx: ctxt, t: t, local_hash: @str) -> u64 { ReEarlyBound(*) | ReLateBound(*) | ReFree(*) | - ReStatic(*) | + ReScope(*) | ReInfer(*) => { tcx.sess.bug("non-static region found when hashing a type") } From 044dec4cf555e8c8f54d8de2f285201f4cdc2840 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 8 Nov 2013 22:25:22 -0500 Subject: [PATCH 13/16] Fix pretty printer when there are multiple lifetime parameters --- src/libsyntax/print/pprust.rs | 19 +++++++++++++------ ...ns-variance-invariant-use-contravariant.rs | 2 +- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index 7b02d036511aa..ed8eb4b542710 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -1572,17 +1572,24 @@ fn print_path_(s: @ps, } word(s.s, "<"); + let mut comma = false; for lifetime in segment.lifetimes.iter() { - print_lifetime(s, lifetime); - if !segment.types.is_empty() { + if comma { word_space(s, ",") } + print_lifetime(s, lifetime); + comma = true; } - commasep(s, - inconsistent, - segment.types.map_to_vec(|t| (*t).clone()), - print_type); + if !segment.types.is_empty() { + if comma { + word_space(s, ",") + } + commasep(s, + inconsistent, + segment.types.map_to_vec(|t| (*t).clone()), + print_type); + } word(s.s, ">") } diff --git a/src/test/compile-fail/regions-variance-invariant-use-contravariant.rs b/src/test/compile-fail/regions-variance-invariant-use-contravariant.rs index 2180964083250..0790c3f956a11 100644 --- a/src/test/compile-fail/regions-variance-invariant-use-contravariant.rs +++ b/src/test/compile-fail/regions-variance-invariant-use-contravariant.rs @@ -27,7 +27,7 @@ fn use_<'short,'long>(c: Invariant<'long>, // 'short <= 'long, this would be true if the Invariant type were // contravariant with respect to its parameter 'a. - let _: Invariant<'short> = c; //~ ERROR lifetime mistach + let _: Invariant<'short> = c; //~ ERROR mismatched types } fn main() { } From b32845d984868ded96d7d6f4d9ab16f0d6befc8b Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Sat, 9 Nov 2013 07:57:10 -0500 Subject: [PATCH 14/16] xfail-fast regions-mock-tcx.rs --- src/test/run-pass/regions-mock-tcx.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/test/run-pass/regions-mock-tcx.rs b/src/test/run-pass/regions-mock-tcx.rs index f98e475094cac..f43b12229bcd4 100644 --- a/src/test/run-pass/regions-mock-tcx.rs +++ b/src/test/run-pass/regions-mock-tcx.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// xfail-fast `use` standards don't resolve + // Test a sample usage pattern for regions. Makes use of the // following features: // From a15196c53bddc77ce1012dc237149d8adb767c30 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Sat, 9 Nov 2013 09:13:58 -0500 Subject: [PATCH 15/16] Make main public to accommodate check-fast --- .../regions-variance-contravariant-use-contravariant.rs | 2 +- src/test/run-pass/regions-variance-covariant-use-covariant.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/run-pass/regions-variance-contravariant-use-contravariant.rs b/src/test/run-pass/regions-variance-contravariant-use-contravariant.rs index 1cc9a501ab6f4..ffc2f07a1530e 100644 --- a/src/test/run-pass/regions-variance-contravariant-use-contravariant.rs +++ b/src/test/run-pass/regions-variance-contravariant-use-contravariant.rs @@ -29,4 +29,4 @@ fn use_<'a>(c: Contravariant<'a>) { fn collapse<'b>(x: &'b int, c: Contravariant<'b>) { } } -fn main() {} +pub fn main() {} diff --git a/src/test/run-pass/regions-variance-covariant-use-covariant.rs b/src/test/run-pass/regions-variance-covariant-use-covariant.rs index ca32f7a52581a..7e0ca41501833 100644 --- a/src/test/run-pass/regions-variance-covariant-use-covariant.rs +++ b/src/test/run-pass/regions-variance-covariant-use-covariant.rs @@ -26,4 +26,4 @@ fn use_<'a>(c: Covariant<'a>) { let _: Covariant<'static> = c; } -fn main() {} +pub fn main() {} From f6e8d49a1a3cd67933c7efebfe7a0c55470049f3 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Sat, 9 Nov 2013 11:34:05 -0500 Subject: [PATCH 16/16] Make irrelevant changes to regions-mock-tcx to convince the pretty printer to emit the same thing twice in a row --- src/test/run-pass/regions-mock-tcx.rs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/test/run-pass/regions-mock-tcx.rs b/src/test/run-pass/regions-mock-tcx.rs index f43b12229bcd4..50a71278c0656 100644 --- a/src/test/run-pass/regions-mock-tcx.rs +++ b/src/test/run-pass/regions-mock-tcx.rs @@ -93,7 +93,6 @@ enum AstKind<'ast> { ExprInt, ExprVar(uint), ExprLambda(Ast<'ast>), - // ... } fn compute_types<'tcx,'ast>(tcx: &mut TypeContext<'tcx,'ast>, @@ -104,15 +103,12 @@ fn compute_types<'tcx,'ast>(tcx: &mut TypeContext<'tcx,'ast>, let ty = tcx.add_type(TypeInt); tcx.set_type(ast.id, ty) } - ExprLambda(ast) => { let arg_ty = tcx.add_type(TypeInt); let body_ty = compute_types(tcx, ast); let lambda_ty = tcx.add_type(TypeFunction(arg_ty, body_ty)); tcx.set_type(ast.id, lambda_ty) } - - // ... } }