From bc21a5ddbe70b2a0c68db9e632ee7e78de9fa59e Mon Sep 17 00:00:00 2001 From: Patrick Walton Date: Thu, 15 Mar 2012 16:36:58 -0700 Subject: [PATCH] rustc: Create self region bindings, and forbid the self region from being used in places it shouldn't be --- src/rustc/metadata/tyencode.rs | 3 +++ src/rustc/middle/region.rs | 46 ++++++++++++++++++++++++++++------ src/rustc/middle/regionck.rs | 4 ++- src/rustc/middle/ty.rs | 6 +++-- src/rustc/middle/typeck.rs | 13 ++++++---- src/rustc/util/ppaux.rs | 1 + 6 files changed, 57 insertions(+), 16 deletions(-) diff --git a/src/rustc/metadata/tyencode.rs b/src/rustc/metadata/tyencode.rs index 4dd229c7dd2..31270053078 100644 --- a/src/rustc/metadata/tyencode.rs +++ b/src/rustc/metadata/tyencode.rs @@ -103,6 +103,9 @@ fn enc_region(w: io::writer, cx: @ctxt, r: ty::region) { ty::re_block(nid) { w.write_char('b'); w.write_int(nid); w.write_char('|'); } + ty::re_self(did) { + w.write_char('s'); w.write_str(cx.ds(did)); w.write_char('|'); + } ty::re_inferred { w.write_char('?'); } } } diff --git a/src/rustc/middle/region.rs b/src/rustc/middle/region.rs index 0b33b6e2631..e1b467ece01 100644 --- a/src/rustc/middle/region.rs +++ b/src/rustc/middle/region.rs @@ -65,13 +65,19 @@ type ctxt = { parent: parent, /* True if we're within the pattern part of an alt, false otherwise. */ - in_alt: bool + in_alt: bool, + + /* + * Points to the site of the current typeclass implementation, or none if + * we're outside one. + */ + self_binding: option }; fn region_to_scope(region_map: @region_map, region: ty::region) -> ast::node_id { ret alt region { - ty::re_caller(def_id) { def_id.node } + ty::re_caller(def_id) | ty::re_self(def_id) { def_id.node } ty::re_named(def_id) { region_map.region_name_to_fn.get(def_id) } ty::re_block(node_id) { node_id } ty::re_inferred { fail "unresolved region in region_to_scope" } @@ -115,7 +121,21 @@ fn resolve_ty(ty: @ast::ty, cx: ctxt, visitor: visit::vt) { alt ty.node { ast::ty_rptr({id: region_id, node: node}, _) { alt node { - ast::re_inferred | ast::re_self { /* no-op */ } + ast::re_inferred { /* no-op */ } + ast::re_self { + alt cx.self_binding { + some(def_id) { + let region = ty::re_self(def_id); + let rm = cx.region_map; + rm.ast_type_to_region.insert(region_id, region); + } + none { + cx.sess.span_err(ty.span, + "the `self` region is not \ + allowed here"); + } + } + } ast::re_named(ident) { // If at item scope, introduce or reuse a binding. If at // block scope, require that the binding be introduced. @@ -281,13 +301,22 @@ fn resolve_local(local: @ast::local, cx: ctxt, visitor: visit::vt) { fn resolve_item(item: @ast::item, cx: ctxt, visitor: visit::vt) { // Items create a new outer block scope as far as we're concerned. - let parent = alt item.node { - ast::item_fn(_, _, _) | ast::item_enum(_, _) { pa_fn_item(item.id) } - _ { pa_item(item.id) } + let parent; + let mut self_binding = cx.self_binding; + alt item.node { + ast::item_fn(_, _, _) | ast::item_enum(_, _) { + parent = pa_fn_item(item.id); + } + ast::item_impl(_, _, _, _) { + self_binding = some({crate: ast::local_crate, node: item.id}); + parent = pa_item(item.id); + } + _ { parent = pa_item(item.id); } }; let new_cx: ctxt = {bindings: @list::nil, parent: parent, - in_alt: false + in_alt: false, + self_binding: self_binding with cx}; visit::visit_item(item, new_cx, visitor); } @@ -307,7 +336,8 @@ fn resolve_crate(sess: session, def_map: resolve::def_map, crate: @ast::crate) mut bindings: @list::nil, mut queued_locals: [], parent: pa_crate, - in_alt: false}; + in_alt: false, + self_binding: none}; let visitor = visit::mk_vt(@{ visit_block: resolve_block, visit_item: resolve_item, diff --git a/src/rustc/middle/regionck.rs b/src/rustc/middle/regionck.rs index 1b73704c301..42d9a51dd47 100644 --- a/src/rustc/middle/regionck.rs +++ b/src/rustc/middle/regionck.rs @@ -28,7 +28,9 @@ fn check_expr(expr: @ast::expr, cx: ctxt, visitor: visit::vt) { alt ty::get(t).struct { ty::ty_rptr(region, _) { alt region { - ty::re_named(_) | ty::re_caller(_) { /* ok */ } + ty::re_named(_) | ty::re_caller(_) | ty::re_self(_) { + /* ok */ + } ty::re_block(rbi) { let referent_block_id = rbi; let enclosing_block_id = alt cx.enclosing_block { diff --git a/src/rustc/middle/ty.rs b/src/rustc/middle/ty.rs index 74dc8dde5fc..9d581287470 100644 --- a/src/rustc/middle/ty.rs +++ b/src/rustc/middle/ty.rs @@ -233,6 +233,7 @@ type fn_ty = {proto: ast::proto, enum region { re_named(def_id), re_caller(def_id), + re_self(def_id), re_block(node_id), re_inferred /* currently unresolved (for typedefs) */ } @@ -1152,8 +1153,9 @@ fn hash_type_structure(st: sty) -> uint { alt r { re_named(_) { 1u } re_caller(_) { 2u } - re_block(_) { 3u } - re_inferred { 4u } + re_self(_) { 3u } + re_block(_) { 4u } + re_inferred { 5u } } } alt st { diff --git a/src/rustc/middle/typeck.rs b/src/rustc/middle/typeck.rs index 1e092a6eb78..5bfca5805ce 100644 --- a/src/rustc/middle/typeck.rs +++ b/src/rustc/middle/typeck.rs @@ -254,10 +254,11 @@ fn ast_ty_to_ty(tcx: ty::ctxt, mode: mode, &&ast_ty: @ast::ty) -> ty::t { fn subst_inferred_regions(tcx: ty::ctxt, use_site: ast::node_id, ty: ty::t) -> ty::t { ret ty::fold_ty(tcx, ty::fm_rptr({|r| - if r == ty::re_inferred { - tcx.region_map.ast_type_to_inferred_region.get(use_site) - } else { - r + alt r { + ty::re_inferred | ty::re_self(_) { + tcx.region_map.ast_type_to_inferred_region.get(use_site) + } + _ { r } } }), ty); } @@ -1462,7 +1463,9 @@ fn instantiate_self_regions(pcx: pat_ctxt, args: [ty::t]) -> [ty::t] { if ty::type_has_rptrs(arg_ty) { ty::fold_ty(pcx.fcx.ccx.tcx, ty::fm_rptr({|r| alt r { - ty::re_inferred | ty::re_caller(_) { pcx.pat_region } + ty::re_inferred | ty::re_caller(_) | ty::re_self(_) { + pcx.pat_region + } _ { r } } }), arg_ty) diff --git a/src/rustc/util/ppaux.rs b/src/rustc/util/ppaux.rs index 0541c0d9d15..a08796d7f36 100644 --- a/src/rustc/util/ppaux.rs +++ b/src/rustc/util/ppaux.rs @@ -73,6 +73,7 @@ fn ty_to_str(cx: ctxt, typ: t) -> str { re_named(_) { "." } // TODO: include name re_caller(_) { "." } re_block(_) { "." } // TODO: include line number + re_self(_) { "self." } re_inferred { "" } } }