Skip to content

Commit

Permalink
librustc: Implement the fully-expanded, UFCS form of explicit self.
Browse files Browse the repository at this point in the history
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 Jul 17, 2014
1 parent 459ffc2 commit 357d5cd
Show file tree
Hide file tree
Showing 25 changed files with 633 additions and 157 deletions.
3 changes: 2 additions & 1 deletion src/librustc/metadata/csearch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
25 changes: 14 additions & 11 deletions src/librustc/metadata/decoder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -724,7 +724,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,
Expand All @@ -738,12 +738,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(special_idents::self_),
'~' => ast::SelfUniq(special_idents::self_),
's' => ty::StaticExplicitSelfCategory,
'v' => ty::ByValueExplicitSelfCategory,
'~' => ty::ByBoxExplicitSelfCategory,
// FIXME(#4846) expl. region
'&' => ast::SelfRegion(None, get_mutability(string.as_bytes()[1]),
special_idents::self_),
'&' => {
ty::ByReferenceExplicitSelfCategory(
ty::ReEmpty,
get_mutability(string.as_bytes()[1]))
}
_ => fail!("unknown self type code: `{}`", explicit_self_kind as char)
}
}
Expand All @@ -761,11 +764,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);
Expand Down
31 changes: 19 additions & 12 deletions src/librustc/metadata/encoder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
}
Expand All @@ -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);
}
}
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -748,10 +755,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))
Expand Down Expand Up @@ -1206,7 +1213,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));
Expand All @@ -1233,7 +1240,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);
Expand Down
10 changes: 10 additions & 0 deletions src/librustc/middle/region.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
Expand Down
67 changes: 54 additions & 13 deletions src/librustc/middle/resolve.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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::*;
Expand Down Expand Up @@ -287,6 +288,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.
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -1361,17 +1381,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)
}
};

Expand All @@ -1382,8 +1404,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);
Expand Down Expand Up @@ -1670,7 +1693,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);
Expand Down Expand Up @@ -3678,6 +3705,13 @@ impl<'a> Resolver<'a> {
this.resolve_type(&*argument.ty);
}

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

this.resolve_type(&*ty_m.decl.output);
});
}
Expand Down Expand Up @@ -4009,7 +4043,14 @@ impl<'a> Resolver<'a> {
method.id,
rib_kind);

self.resolve_function(rib_kind, Some(method.pe_fn_decl()), type_parameters,
match method.pe_explicit_self().node {
SelfExplicit(ref typ, _) => self.resolve_type(*typ),
_ => {}
}

self.resolve_function(rib_kind,
Some(method.pe_fn_decl()),
type_parameters,
method.pe_body());
}

Expand Down Expand Up @@ -4765,7 +4806,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 \
Expand Down Expand Up @@ -5037,7 +5078,7 @@ impl<'a> Resolver<'a> {
let path_str = self.path_idents_to_string(&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 => {}
}
Expand Down
15 changes: 6 additions & 9 deletions src/librustc/middle/trans/meth.rs
Original file line number Diff line number Diff line change
Expand Up @@ -502,15 +502,12 @@ fn emit_vtable_methods(bcx: &Block,
ExprId(0),
substs.clone(),
vtables.clone());
match m.explicit_self {
ast::SelfValue(_) => {
fn_ref = trans_unboxing_shim(bcx,
fn_ref,
&*m,
m_id,
substs.clone());
},
_ => {}
if m.explicit_self == ty::ByValueExplicitSelfCategory {
fn_ref = trans_unboxing_shim(bcx,
fn_ref,
&*m,
m_id,
substs.clone());
}
fn_ref
}
Expand Down
18 changes: 16 additions & 2 deletions src/librustc/middle/ty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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,
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -1055,6 +1058,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,
Expand Down Expand Up @@ -4767,3 +4771,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,
}

Loading

0 comments on commit 357d5cd

Please sign in to comment.