Skip to content
Permalink
Browse files

librustc: Implement the fully-expanded, UFCS form of explicit self.

This makes two changes to region inference: (1) it allows region
inference to relate early-bound regions; and (2) it allows regions to be
related before variance runs. The former is needed because there is no
relation between the two regions before region substitution happens,
while the latter is needed because type collection has to run before
variance. We assume that, before variance is inferred, that lifetimes
are invariant. This is a conservative overapproximation.

This relates to rust-lang#13885. This does not remove `~self` from the language
yet, however.

[breaking-change]
  • Loading branch information...
pcwalton committed May 6, 2014
1 parent c175ed4 commit 130baf8ba640eeb15bf7498eb8a27eb36ef94c11
@@ -132,7 +132,8 @@ pub fn get_method(tcx: &ty::ctxt, def: ast::DefId) -> ty::Method {

pub fn get_method_name_and_explicit_self(cstore: &cstore::CStore,
def: ast::DefId)
-> (ast::Ident, ast::ExplicitSelf_)
-> (ast::Ident,
ty::ExplicitSelfCategory)
{
let cdata = cstore.get_crate_data(def.krate);
decoder::get_method_name_and_explicit_self(cstore.intr.clone(), &*cdata, def.node)
@@ -744,7 +744,7 @@ pub fn get_enum_variants(intr: Rc<IdentInterner>, cdata: Cmd, id: ast::NodeId,
}).collect()
}

fn get_explicit_self(item: ebml::Doc) -> ast::ExplicitSelf_ {
fn get_explicit_self(item: ebml::Doc) -> ty::ExplicitSelfCategory {
fn get_mutability(ch: u8) -> ast::Mutability {
match ch as char {
'i' => ast::MutImmutable,
@@ -758,11 +758,15 @@ fn get_explicit_self(item: ebml::Doc) -> ast::ExplicitSelf_ {

let explicit_self_kind = string.as_bytes()[0];
match explicit_self_kind as char {
's' => ast::SelfStatic,
'v' => ast::SelfValue,
'~' => ast::SelfUniq,
's' => ty::StaticExplicitSelfCategory,
'v' => ty::ByValueExplicitSelfCategory,
'~' => ty::ByBoxExplicitSelfCategory,
// FIXME(#4846) expl. region
'&' => ast::SelfRegion(None, get_mutability(string.as_bytes()[1])),
'&' => {
ty::ByReferenceExplicitSelfCategory(
ty::ReEmpty,
get_mutability(string.as_bytes()[1]))
}
_ => fail!("unknown self type code: `{}`", explicit_self_kind as char)
}
}
@@ -780,11 +784,11 @@ pub fn get_impl_methods(cdata: Cmd, impl_id: ast::NodeId) -> Vec<ast::DefId> {
methods
}

pub fn get_method_name_and_explicit_self(
intr: Rc<IdentInterner>,
cdata: Cmd,
id: ast::NodeId) -> (ast::Ident, ast::ExplicitSelf_)
{
pub fn get_method_name_and_explicit_self(intr: Rc<IdentInterner>,
cdata: Cmd,
id: ast::NodeId)
-> (ast::Ident,
ty::ExplicitSelfCategory) {
let method_doc = lookup_item(id, cdata.data());
let name = item_name(&*intr, method_doc);
let explicit_self = get_explicit_self(method_doc);
@@ -402,7 +402,7 @@ fn encode_reexported_static_base_methods(ecx: &EncodeContext,
for base_impl_did in implementations.borrow().iter() {
for &method_did in impl_methods.get(base_impl_did).iter() {
let m = ty::method(ecx.tcx, method_did);
if m.explicit_self == ast::SelfStatic {
if m.explicit_self == ty::StaticExplicitSelfCategory {
encode_reexported_static_method(ebml_w, exp, m.def_id, m.ident);
}
}
@@ -421,7 +421,7 @@ fn encode_reexported_static_trait_methods(ecx: &EncodeContext,
match ecx.tcx.trait_methods_cache.borrow().find(&exp.def_id) {
Some(methods) => {
for m in methods.iter() {
if m.explicit_self == ast::SelfStatic {
if m.explicit_self == ty::StaticExplicitSelfCategory {
encode_reexported_static_method(ebml_w, exp, m.def_id, m.ident);
}
}
@@ -623,15 +623,22 @@ fn encode_visibility(ebml_w: &mut Encoder, visibility: Visibility) {
ebml_w.end_tag();
}

fn encode_explicit_self(ebml_w: &mut Encoder, explicit_self: ast::ExplicitSelf_) {
fn encode_explicit_self(ebml_w: &mut Encoder,
explicit_self: &ty::ExplicitSelfCategory) {
ebml_w.start_tag(tag_item_trait_method_explicit_self);

// Encode the base self type.
match explicit_self {
SelfStatic => { ebml_w.writer.write(&[ 's' as u8 ]); }
SelfValue => { ebml_w.writer.write(&[ 'v' as u8 ]); }
SelfUniq => { ebml_w.writer.write(&[ '~' as u8 ]); }
SelfRegion(_, m) => {
match *explicit_self {
ty::StaticExplicitSelfCategory => {
ebml_w.writer.write(&[ 's' as u8 ]);
}
ty::ByValueExplicitSelfCategory => {
ebml_w.writer.write(&[ 'v' as u8 ]);
}
ty::ByBoxExplicitSelfCategory => {
ebml_w.writer.write(&[ '~' as u8 ]);
}
ty::ByReferenceExplicitSelfCategory(_, m) => {
// FIXME(#4846) encode custom lifetime
ebml_w.writer.write(&['&' as u8]);
encode_mutability(ebml_w, m);
@@ -744,10 +751,10 @@ fn encode_method_ty_fields(ecx: &EncodeContext,
tag_item_method_tps);
encode_method_fty(ecx, ebml_w, &method_ty.fty);
encode_visibility(ebml_w, method_ty.vis);
encode_explicit_self(ebml_w, method_ty.explicit_self);
encode_explicit_self(ebml_w, &method_ty.explicit_self);
let fn_style = method_ty.fty.fn_style;
match method_ty.explicit_self {
ast::SelfStatic => {
ty::StaticExplicitSelfCategory => {
encode_family(ebml_w, fn_style_static_method_family(fn_style));
}
_ => encode_family(ebml_w, style_fn_family(fn_style))
@@ -1215,7 +1222,7 @@ fn encode_info_for_item(ecx: &EncodeContext,
encode_path(ebml_w, path.clone().chain(Some(elem).move_iter()));

match method_ty.explicit_self {
SelfStatic => {
ty::StaticExplicitSelfCategory => {
encode_family(ebml_w,
fn_style_static_method_family(
method_ty.fty.fn_style));
@@ -1242,7 +1249,7 @@ fn encode_info_for_item(ecx: &EncodeContext,
encode_attributes(ebml_w, m.attrs.as_slice());
// If this is a static method, we've already encoded
// this.
if method_ty.explicit_self != SelfStatic {
if method_ty.explicit_self != ty::StaticExplicitSelfCategory {
// FIXME: I feel like there is something funny going on.
let pty = ty::lookup_item_type(tcx, method_def_id);
encode_bounds_and_type(ebml_w, ecx, &pty);
@@ -314,6 +314,16 @@ impl RegionMaps {
self.sub_free_region(sub_fr, super_fr)
}

(ty::ReEarlyBound(param_id_a, param_space_a, index_a, _),
ty::ReEarlyBound(param_id_b, param_space_b, index_b, _)) => {
// This case is used only to make sure that explicitly-
// specified `Self` types match the real self type in
// implementations.
param_id_a == param_id_b &&
param_space_a == param_space_b &&
index_a == index_b
}

_ => {
false
}
@@ -11,13 +11,14 @@
#![allow(non_camel_case_types)]

use driver::session::Session;
use lint;
use metadata::csearch;
use metadata::decoder::{DefLike, DlDef, DlField, DlImpl};
use middle::def::*;
use middle::lang_items::LanguageItems;
use middle::pat_util::pat_bindings;
use middle::subst::{ParamSpace, FnSpace, TypeSpace};
use lint;
use middle::ty::{ExplicitSelfCategory, StaticExplicitSelfCategory};
use util::nodemap::{NodeMap, DefIdSet, FnvHashMap};

use syntax::ast::*;
@@ -286,6 +287,24 @@ enum ModulePrefixResult {
PrefixFound(Rc<Module>, uint)
}

#[deriving(Clone, Eq, PartialEq)]
enum MethodIsStaticFlag {
MethodIsNotStatic,
MethodIsStatic,
}

impl MethodIsStaticFlag {
fn from_explicit_self_category(explicit_self_category:
ExplicitSelfCategory)
-> MethodIsStaticFlag {
if explicit_self_category == StaticExplicitSelfCategory {
MethodIsStatic
} else {
MethodIsNotStatic
}
}
}

#[deriving(PartialEq)]
enum NameSearchType {
/// We're doing a name search in order to resolve a `use` directive.
@@ -805,7 +824,8 @@ struct Resolver<'a> {

graph_root: NameBindings,

method_map: RefCell<FnvHashMap<(Name, DefId), ast::ExplicitSelf_>>,
method_map: RefCell<FnvHashMap<(Name, DefId), MethodIsStaticFlag>>,

structs: FnvHashMap<DefId, Vec<Name>>,

// The number of imports that are currently unresolved.
@@ -1349,17 +1369,19 @@ impl<'a> Resolver<'a> {
let ident = ty_m.ident;

// Add it as a name in the trait module.
let def = match ty_m.explicit_self.node {
let (def, static_flag) = match ty_m.explicit_self.node {
SelfStatic => {
// Static methods become `def_static_method`s.
DefStaticMethod(local_def(ty_m.id),
(DefStaticMethod(local_def(ty_m.id),
FromTrait(local_def(item.id)),
ty_m.fn_style)
ty_m.fn_style),
MethodIsStatic)
}
_ => {
// Non-static methods become `def_method`s.
DefMethod(local_def(ty_m.id),
Some(local_def(item.id)))
(DefMethod(local_def(ty_m.id),
Some(local_def(item.id))),
MethodIsNotStatic)
}
};

@@ -1370,8 +1392,9 @@ impl<'a> Resolver<'a> {
ty_m.span);
method_name_bindings.define_value(def, ty_m.span, true);

self.method_map.borrow_mut().insert((ident.name, def_id),
ty_m.explicit_self.node);
self.method_map
.borrow_mut()
.insert((ident.name, def_id), static_flag);
}

name_bindings.define_type(DefTrait(def_id), sp, is_public);
@@ -1658,7 +1681,11 @@ impl<'a> Resolver<'a> {
trait method '{}'",
token::get_ident(method_name));

self.method_map.borrow_mut().insert((method_name.name, def_id), explicit_self);
self.method_map
.borrow_mut()
.insert((method_name.name, def_id),
MethodIsStaticFlag::from_explicit_self_category(
explicit_self));

if is_exported {
self.external_exports.insert(method_def_id);
@@ -3986,6 +4013,11 @@ impl<'a> Resolver<'a> {
method.id,
rib_kind);

match method.explicit_self.node {
SelfExplicit(ref typ) => self.resolve_type(*typ),
_ => {}
}

self.resolve_function(rib_kind, Some(method.decl), type_parameters, method.body);
}

@@ -4741,7 +4773,7 @@ impl<'a> Resolver<'a> {
match containing_module.def_id.get() {
Some(def_id) => {
match self.method_map.borrow().find(&(ident.name, def_id)) {
Some(x) if *x == SelfStatic => (),
Some(&MethodIsStatic) => (),
None => (),
_ => {
debug!("containing module was a trait or impl \
@@ -5013,7 +5045,7 @@ impl<'a> Resolver<'a> {
let path_str = self.path_idents_to_str(&trait_ref.path);

match method_map.find(&(name, did)) {
Some(&SelfStatic) => return StaticTraitMethod(path_str),
Some(&MethodIsStatic) => return StaticTraitMethod(path_str),
Some(_) => return TraitMethod,
None => {}
}
@@ -502,7 +502,7 @@ fn emit_vtable_methods(bcx: &Block,
ExprId(0),
substs.clone(),
vtables.clone());
if m.explicit_self == ast::SelfValue {
if m.explicit_self == ty::ByValueExplicitSelfCategory {
fn_ref = trans_unboxing_shim(bcx,
fn_ref,
&*m,
@@ -85,7 +85,7 @@ pub struct Method {
pub ident: ast::Ident,
pub generics: ty::Generics,
pub fty: BareFnTy,
pub explicit_self: ast::ExplicitSelf_,
pub explicit_self: ExplicitSelfCategory,
pub vis: ast::Visibility,
pub def_id: ast::DefId,
pub container: MethodContainer,
@@ -98,7 +98,7 @@ impl Method {
pub fn new(ident: ast::Ident,
generics: ty::Generics,
fty: BareFnTy,
explicit_self: ast::ExplicitSelf_,
explicit_self: ExplicitSelfCategory,
vis: ast::Visibility,
def_id: ast::DefId,
container: MethodContainer,
@@ -311,6 +311,9 @@ pub struct ctxt {
/// (inferred) variance.
pub item_variance_map: RefCell<DefIdMap<Rc<ItemVariances>>>,

/// True if the variance has been computed yet; false otherwise.
pub variance_computed: Cell<bool>,

/// 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
@@ -1050,6 +1053,7 @@ pub fn mk_ctxt(s: Session,
ctxt {
named_region_map: named_region_map,
item_variance_map: RefCell::new(DefIdMap::new()),
variance_computed: Cell::new(false),
interner: RefCell::new(FnvHashMap::new()),
next_id: Cell::new(primitives::LAST_PRIMITIVE_ID),
sess: s,
@@ -4759,3 +4763,13 @@ impl mc::Typer for ty::ctxt {
self.upvar_borrow_map.borrow().get_copy(&upvar_id)
}
}

/// The category of explicit self.
#[deriving(Clone, Eq, PartialEq)]
pub enum ExplicitSelfCategory {
StaticExplicitSelfCategory,
ByValueExplicitSelfCategory,
ByReferenceExplicitSelfCategory(Region, ast::Mutability),
ByBoxExplicitSelfCategory,
}

0 comments on commit 130baf8

Please sign in to comment.
You can’t perform that action at this time.