Infer variance of types with respect to the region parameter.
A similar approach could be used for type parameters. Fixes #2282.
This commit is contained in:
@@ -770,6 +770,7 @@ enum AncestorList = option<unsafe::Exclusive<AncestorNode>>;
|
|||||||
fn access_group<U>(x: &TaskGroupArc, blk: fn(TaskGroupInner) -> U) -> U {
|
fn access_group<U>(x: &TaskGroupArc, blk: fn(TaskGroupInner) -> U) -> U {
|
||||||
unsafe { x.with(blk) }
|
unsafe { x.with(blk) }
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn access_ancestors<U>(x: &unsafe::Exclusive<AncestorNode>,
|
fn access_ancestors<U>(x: &unsafe::Exclusive<AncestorNode>,
|
||||||
blk: fn(x: &mut AncestorNode) -> U) -> U {
|
blk: fn(x: &mut AncestorNode) -> U) -> U {
|
||||||
|
|||||||
@@ -299,7 +299,20 @@ fn node_id_to_str(map: map, id: node_id, itr: ident_interner) -> ~str {
|
|||||||
fmt!{"unknown node (id=%d)", id}
|
fmt!{"unknown node (id=%d)", id}
|
||||||
}
|
}
|
||||||
some(node_item(item, path)) => {
|
some(node_item(item, path)) => {
|
||||||
fmt!{"item %s (id=%?)", path_ident_to_str(*path, item.ident, itr), id}
|
let path_str = path_ident_to_str(*path, item.ident, itr);
|
||||||
|
let item_str = match item.node {
|
||||||
|
item_const(*) => ~"const",
|
||||||
|
item_fn(*) => ~"fn",
|
||||||
|
item_mod(*) => ~"mod",
|
||||||
|
item_foreign_mod(*) => ~"foreign mod",
|
||||||
|
item_ty(*) => ~"ty",
|
||||||
|
item_enum(*) => ~"enum",
|
||||||
|
item_class(*) => ~"class",
|
||||||
|
item_trait(*) => ~"trait",
|
||||||
|
item_impl(*) => ~"impl",
|
||||||
|
item_mac(*) => ~"macro"
|
||||||
|
};
|
||||||
|
fmt!("%s %s (id=%?)", item_str, path_str, id)
|
||||||
}
|
}
|
||||||
some(node_foreign_item(item, abi, path)) => {
|
some(node_foreign_item(item, abi, path)) => {
|
||||||
fmt!{"foreign item %s with abi %? (id=%?)",
|
fmt!{"foreign item %s with abi %? (id=%?)",
|
||||||
|
|||||||
@@ -127,7 +127,7 @@ fn get_type(tcx: ty::ctxt, def: ast::def_id) -> ty::ty_param_bounds_and_ty {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn get_region_param(cstore: metadata::cstore::cstore,
|
fn get_region_param(cstore: metadata::cstore::cstore,
|
||||||
def: ast::def_id) -> bool {
|
def: ast::def_id) -> option<ty::region_variance> {
|
||||||
let cdata = cstore::get_crate_data(cstore, def.crate);
|
let cdata = cstore::get_crate_data(cstore, def.crate);
|
||||||
return decoder::get_region_param(cdata, def.node);
|
return decoder::get_region_param(cdata, def.node);
|
||||||
}
|
}
|
||||||
@@ -149,7 +149,9 @@ fn get_field_type(tcx: ty::ctxt, class_id: ast::def_id,
|
|||||||
class_id, def} );
|
class_id, def} );
|
||||||
debug!{"got field data %?", the_field};
|
debug!{"got field data %?", the_field};
|
||||||
let ty = decoder::item_type(def, the_field, tcx, cdata);
|
let ty = decoder::item_type(def, the_field, tcx, cdata);
|
||||||
return {bounds: @~[], rp: false, ty: ty};
|
return {bounds: @~[],
|
||||||
|
region_param: none,
|
||||||
|
ty: ty};
|
||||||
}
|
}
|
||||||
|
|
||||||
// Given a def_id for an impl or class, return the traits it implements,
|
// Given a def_id for an impl or class, return the traits it implements,
|
||||||
|
|||||||
@@ -237,11 +237,11 @@ fn item_ty_param_bounds(item: ebml::doc, tcx: ty::ctxt, cdata: cmd)
|
|||||||
@bounds
|
@bounds
|
||||||
}
|
}
|
||||||
|
|
||||||
fn item_ty_region_param(item: ebml::doc) -> bool {
|
fn item_ty_region_param(item: ebml::doc) -> option<ty::region_variance> {
|
||||||
match ebml::maybe_get_doc(item, tag_region_param) {
|
ebml::maybe_get_doc(item, tag_region_param).map(|doc| {
|
||||||
some(_) => true,
|
let d = ebml::ebml_deserializer(doc);
|
||||||
none => false
|
ty::deserialize_region_variance(d)
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn item_ty_param_count(item: ebml::doc) -> uint {
|
fn item_ty_param_count(item: ebml::doc) -> uint {
|
||||||
@@ -340,10 +340,14 @@ fn get_type(cdata: cmd, id: ast::node_id, tcx: ty::ctxt)
|
|||||||
item_ty_param_bounds(item, tcx, cdata)
|
item_ty_param_bounds(item, tcx, cdata)
|
||||||
} else { @~[] };
|
} else { @~[] };
|
||||||
let rp = item_ty_region_param(item);
|
let rp = item_ty_region_param(item);
|
||||||
return {bounds: tp_bounds, rp: rp, ty: t};
|
return {bounds: tp_bounds,
|
||||||
|
region_param: rp,
|
||||||
|
ty: t};
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_region_param(cdata: cmd, id: ast::node_id) -> bool {
|
fn get_region_param(cdata: cmd, id: ast::node_id)
|
||||||
|
-> option<ty::region_variance> {
|
||||||
|
|
||||||
let item = lookup_item(id, cdata.data);
|
let item = lookup_item(id, cdata.data);
|
||||||
return item_ty_region_param(item);
|
return item_ty_region_param(item);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -81,8 +81,12 @@ fn encode_def_id(ebml_w: ebml::writer, id: def_id) {
|
|||||||
|
|
||||||
fn encode_region_param(ecx: @encode_ctxt, ebml_w: ebml::writer,
|
fn encode_region_param(ecx: @encode_ctxt, ebml_w: ebml::writer,
|
||||||
it: @ast::item) {
|
it: @ast::item) {
|
||||||
let rp = ecx.tcx.region_paramd_items.contains_key(it.id);
|
let opt_rp = ecx.tcx.region_paramd_items.find(it.id);
|
||||||
if rp { do ebml_w.wr_tag(tag_region_param) { } }
|
for opt_rp.each |rp| {
|
||||||
|
do ebml_w.wr_tag(tag_region_param) {
|
||||||
|
ty::serialize_region_variance(ebml_w, rp);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn encode_mutability(ebml_w: ebml::writer, mt: class_mutability) {
|
fn encode_mutability(ebml_w: ebml::writer, mt: class_mutability) {
|
||||||
|
|||||||
@@ -601,8 +601,10 @@ impl ebml::writer: ebml_writer_helpers {
|
|||||||
self.emit_bounds(ecx, bs);
|
self.emit_bounds(ecx, bs);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
do self.emit_rec_field(~"rp", 1u) {
|
do self.emit_rec_field(~"region_param", 1u) {
|
||||||
self.emit_bool(tpbt.rp);
|
ty::serialize_opt_region_variance(
|
||||||
|
self,
|
||||||
|
tpbt.region_param);
|
||||||
}
|
}
|
||||||
do self.emit_rec_field(~"ty", 2u) {
|
do self.emit_rec_field(~"ty", 2u) {
|
||||||
self.emit_ty(ecx, tpbt.ty);
|
self.emit_ty(ecx, tpbt.ty);
|
||||||
@@ -817,8 +819,8 @@ impl ebml::ebml_deserializer: ebml_deserializer_decoder_helpers {
|
|||||||
bounds: self.read_rec_field(~"bounds", 0u, || {
|
bounds: self.read_rec_field(~"bounds", 0u, || {
|
||||||
@self.read_to_vec(|| self.read_bounds(xcx) )
|
@self.read_to_vec(|| self.read_bounds(xcx) )
|
||||||
}),
|
}),
|
||||||
rp: self.read_rec_field(~"rp", 1u, || {
|
region_param: self.read_rec_field(~"region_param", 1u, || {
|
||||||
self.read_bool()
|
ty::deserialize_opt_region_variance(self)
|
||||||
}),
|
}),
|
||||||
ty: self.read_rec_field(~"ty", 2u, || {
|
ty: self.read_rec_field(~"ty", 2u, || {
|
||||||
self.read_ty(xcx)
|
self.read_ty(xcx)
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ import syntax::ast_util::new_def_hash;
|
|||||||
import syntax::ast_map;
|
import syntax::ast_map;
|
||||||
import dvec::{DVec, dvec};
|
import dvec::{DVec, dvec};
|
||||||
import metadata::csearch;
|
import metadata::csearch;
|
||||||
|
import ty::{region_variance, rv_covariant, rv_invariant, rv_contravariant};
|
||||||
|
|
||||||
import std::list;
|
import std::list;
|
||||||
import std::list::list;
|
import std::list::list;
|
||||||
@@ -365,8 +366,9 @@ fn resolve_crate(sess: session, def_map: resolve3::DefMap,
|
|||||||
// a worklist. We can then process the worklist, propagating indirect
|
// a worklist. We can then process the worklist, propagating indirect
|
||||||
// dependencies until a fixed point is reached.
|
// dependencies until a fixed point is reached.
|
||||||
|
|
||||||
type region_paramd_items = hashmap<ast::node_id, ()>;
|
type region_paramd_items = hashmap<ast::node_id, region_variance>;
|
||||||
type dep_map = hashmap<ast::node_id, @DVec<ast::node_id>>;
|
type region_dep = {ambient_variance: region_variance, id: ast::node_id};
|
||||||
|
type dep_map = hashmap<ast::node_id, @DVec<region_dep>>;
|
||||||
|
|
||||||
type determine_rp_ctxt_ = {
|
type determine_rp_ctxt_ = {
|
||||||
sess: session,
|
sess: session,
|
||||||
@@ -381,42 +383,98 @@ type determine_rp_ctxt_ = {
|
|||||||
|
|
||||||
// true when we are within an item but not within a method.
|
// true when we are within an item but not within a method.
|
||||||
// see long discussion on region_is_relevant()
|
// see long discussion on region_is_relevant()
|
||||||
mut anon_implies_rp: bool
|
mut anon_implies_rp: bool,
|
||||||
|
|
||||||
|
// encodes the context of the current type; invariant if
|
||||||
|
// mutable, covariant otherwise
|
||||||
|
mut ambient_variance: region_variance,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum determine_rp_ctxt {
|
enum determine_rp_ctxt {
|
||||||
determine_rp_ctxt_(@determine_rp_ctxt_)
|
determine_rp_ctxt_(@determine_rp_ctxt_)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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`.
|
||||||
|
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 determine_rp_ctxt {
|
impl determine_rp_ctxt {
|
||||||
fn add_rp(id: ast::node_id) {
|
fn add_variance(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.
|
||||||
|
fn add_rp(id: ast::node_id, variance: region_variance) {
|
||||||
assert id != 0;
|
assert id != 0;
|
||||||
if self.region_paramd_items.insert(id, ()) {
|
let old_variance = self.region_paramd_items.find(id);
|
||||||
debug!{"add region-parameterized item: %d (%s)", id,
|
let joined_variance = match old_variance {
|
||||||
|
none => variance,
|
||||||
|
some(v) => join_variance(v, variance)
|
||||||
|
};
|
||||||
|
|
||||||
|
debug!["add_rp() variance for %s: %? == %? ^ %?",
|
||||||
ast_map::node_id_to_str(self.ast_map, id,
|
ast_map::node_id_to_str(self.ast_map, id,
|
||||||
self.sess.parse_sess.interner)};
|
self.sess.parse_sess.interner),
|
||||||
|
joined_variance, old_variance, variance];
|
||||||
|
|
||||||
|
if some(joined_variance) != old_variance {
|
||||||
|
self.region_paramd_items.insert(id, joined_variance);
|
||||||
self.worklist.push(id);
|
self.worklist.push(id);
|
||||||
} else {
|
|
||||||
debug!{"item %d already region-parameterized", id};
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_dep(from: ast::node_id, to: ast::node_id) {
|
/// Indicates that the region-parameterization of the current item
|
||||||
debug!{"add dependency from %d -> %d (%s -> %s)",
|
/// is dependent on the region-parameterization of the item
|
||||||
from, to,
|
/// `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.
|
||||||
|
fn add_dep(from: ast::node_id) {
|
||||||
|
debug!["add dependency from %d -> %d (%s -> %s) with variance %?",
|
||||||
|
from, self.item_id,
|
||||||
ast_map::node_id_to_str(self.ast_map, from,
|
ast_map::node_id_to_str(self.ast_map, from,
|
||||||
self.sess.parse_sess.interner),
|
self.sess.parse_sess.interner),
|
||||||
ast_map::node_id_to_str(self.ast_map, to,
|
ast_map::node_id_to_str(self.ast_map, self.item_id,
|
||||||
self.sess.parse_sess.interner)};
|
self.sess.parse_sess.interner),
|
||||||
|
copy self.ambient_variance];
|
||||||
let vec = match self.dep_map.find(from) {
|
let vec = match self.dep_map.find(from) {
|
||||||
some(vec) => {vec}
|
some(vec) => vec,
|
||||||
none => {
|
none => {
|
||||||
let vec = @dvec();
|
let vec = @dvec();
|
||||||
self.dep_map.insert(from, vec);
|
self.dep_map.insert(from, vec);
|
||||||
vec
|
vec
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
if !vec.contains(to) { vec.push(to); }
|
let dep = {ambient_variance: self.ambient_variance, id: self.item_id};
|
||||||
|
if !vec.contains(dep) { vec.push(dep); }
|
||||||
}
|
}
|
||||||
|
|
||||||
// Determines whether a reference to a region that appears in the
|
// Determines whether a reference to a region that appears in the
|
||||||
@@ -460,7 +518,9 @@ impl determine_rp_ctxt {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn with(item_id: ast::node_id, anon_implies_rp: bool, f: fn()) {
|
fn with(item_id: ast::node_id,
|
||||||
|
anon_implies_rp: bool,
|
||||||
|
f: fn()) {
|
||||||
let old_item_id = self.item_id;
|
let old_item_id = self.item_id;
|
||||||
let old_anon_implies_rp = self.anon_implies_rp;
|
let old_anon_implies_rp = self.anon_implies_rp;
|
||||||
self.item_id = item_id;
|
self.item_id = item_id;
|
||||||
@@ -471,6 +531,13 @@ impl determine_rp_ctxt {
|
|||||||
self.item_id = old_item_id;
|
self.item_id = old_item_id;
|
||||||
self.anon_implies_rp = old_anon_implies_rp;
|
self.anon_implies_rp = old_anon_implies_rp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn with_ambient_variance(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(item: @ast::item,
|
fn determine_rp_in_item(item: @ast::item,
|
||||||
@@ -484,12 +551,17 @@ fn determine_rp_in_item(item: @ast::item,
|
|||||||
fn determine_rp_in_fn(fk: visit::fn_kind,
|
fn determine_rp_in_fn(fk: visit::fn_kind,
|
||||||
decl: ast::fn_decl,
|
decl: ast::fn_decl,
|
||||||
body: ast::blk,
|
body: ast::blk,
|
||||||
sp: span,
|
_sp: span,
|
||||||
id: ast::node_id,
|
_id: ast::node_id,
|
||||||
&&cx: determine_rp_ctxt,
|
&&cx: determine_rp_ctxt,
|
||||||
visitor: visit::vt<determine_rp_ctxt>) {
|
visitor: visit::vt<determine_rp_ctxt>) {
|
||||||
do cx.with(cx.item_id, false) {
|
do cx.with(cx.item_id, false) {
|
||||||
visit::visit_fn(fk, decl, body, sp, id, cx, visitor);
|
do cx.with_ambient_variance(rv_contravariant) {
|
||||||
|
for decl.inputs.each |a| { visitor.visit_ty(a.ty, cx, visitor); }
|
||||||
|
}
|
||||||
|
visitor.visit_ty(decl.output, cx, visitor);
|
||||||
|
visitor.visit_ty_params(visit::tps_of_fn(fk), cx, visitor);
|
||||||
|
visitor.visit_block(body, cx, visitor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -511,16 +583,18 @@ fn determine_rp_in_ty(ty: @ast::ty,
|
|||||||
// impl etc. So we can ignore it and its components.
|
// impl etc. So we can ignore it and its components.
|
||||||
if cx.item_id == 0 { return; }
|
if cx.item_id == 0 { return; }
|
||||||
|
|
||||||
// if this type directly references a region, either via a
|
// if this type directly references a region pointer like &r/ty,
|
||||||
// region pointer like &r.ty or a region-parameterized path
|
// add to the worklist/set. Note that &r/ty is contravariant with
|
||||||
// like path/r, add to the worklist/set
|
// respect to &r, because &r/ty can be used whereever a *smaller*
|
||||||
|
// region is expected (and hence is a supertype of those
|
||||||
|
// locations)
|
||||||
match ty.node {
|
match ty.node {
|
||||||
ast::ty_rptr(r, _) |
|
ast::ty_rptr(r, _) => {
|
||||||
ast::ty_path(@{rp: some(r), _}, _) => {
|
debug!["referenced rptr type %s",
|
||||||
debug!{"referenced type with regions %s",
|
pprust::ty_to_str(ty, cx.sess.intr())];
|
||||||
pprust::ty_to_str(ty, cx.sess.intr())};
|
|
||||||
if cx.region_is_relevant(r) {
|
if cx.region_is_relevant(r) {
|
||||||
cx.add_rp(cx.item_id);
|
cx.add_rp(cx.item_id, cx.add_variance(rv_contravariant))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -528,7 +602,7 @@ fn determine_rp_in_ty(ty: @ast::ty,
|
|||||||
ast::ty_fn(ast::proto_block, _, _) if cx.anon_implies_rp => {
|
ast::ty_fn(ast::proto_block, _, _) if cx.anon_implies_rp => {
|
||||||
debug!("referenced bare fn type with regions %s",
|
debug!("referenced bare fn type with regions %s",
|
||||||
pprust::ty_to_str(ty, cx.sess.intr()));
|
pprust::ty_to_str(ty, cx.sess.intr()));
|
||||||
cx.add_rp(cx.item_id);
|
cx.add_rp(cx.item_id, cx.add_variance(rv_contravariant));
|
||||||
}
|
}
|
||||||
|
|
||||||
_ => {}
|
_ => {}
|
||||||
@@ -543,13 +617,16 @@ fn determine_rp_in_ty(ty: @ast::ty,
|
|||||||
match cx.def_map.get(id) {
|
match cx.def_map.get(id) {
|
||||||
ast::def_ty(did) | ast::def_class(did, _) => {
|
ast::def_ty(did) | ast::def_class(did, _) => {
|
||||||
if did.crate == ast::local_crate {
|
if did.crate == ast::local_crate {
|
||||||
cx.add_dep(did.node, cx.item_id);
|
cx.add_dep(did.node);
|
||||||
} else {
|
} else {
|
||||||
let cstore = cx.sess.cstore;
|
let cstore = cx.sess.cstore;
|
||||||
if csearch::get_region_param(cstore, did) {
|
match csearch::get_region_param(cstore, did) {
|
||||||
debug!{"reference to external, rp'd type %s",
|
none => {}
|
||||||
pprust::ty_to_str(ty, cx.sess.intr())};
|
some(variance) => {
|
||||||
cx.add_rp(cx.item_id);
|
debug!["reference to external, rp'd type %s",
|
||||||
|
pprust::ty_to_str(ty, cx.sess.intr())];
|
||||||
|
cx.add_rp(cx.item_id, cx.add_variance(variance))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -560,15 +637,73 @@ fn determine_rp_in_ty(ty: @ast::ty,
|
|||||||
}
|
}
|
||||||
|
|
||||||
match ty.node {
|
match ty.node {
|
||||||
ast::ty_fn(*) => {
|
ast::ty_box(mt) | ast::ty_uniq(mt) | ast::ty_vec(mt) |
|
||||||
|
ast::ty_rptr(_, mt) | ast::ty_ptr(mt) => {
|
||||||
|
visit_mt(mt, cx, visitor);
|
||||||
|
}
|
||||||
|
|
||||||
|
ast::ty_rec(fields) => {
|
||||||
|
for fields.each |field| {
|
||||||
|
visit_mt(field.node.mt, cx, visitor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ast::ty_path(path, _) => {
|
||||||
|
// type parameters are---for now, anyway---always invariant
|
||||||
|
do cx.with_ambient_variance(rv_invariant) {
|
||||||
|
for path.types.each |tp| {
|
||||||
|
visitor.visit_ty(tp, cx, visitor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ast::ty_fn(_, bounds, 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) {
|
do cx.with(cx.item_id, false) {
|
||||||
visit::visit_ty(ty, cx, visitor);
|
// parameters are contravariant
|
||||||
|
do cx.with_ambient_variance(rv_contravariant) {
|
||||||
|
for decl.inputs.each |a| {
|
||||||
|
visitor.visit_ty(a.ty, cx, visitor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
visit::visit_ty_param_bounds(bounds, cx, visitor);
|
||||||
|
visitor.visit_ty(decl.output, cx, visitor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
_ => {
|
_ => {
|
||||||
visit::visit_ty(ty, cx, visitor);
|
visit::visit_ty(ty, cx, visitor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn visit_mt(mt: ast::mt, &&cx: determine_rp_ctxt,
|
||||||
|
visitor: visit::vt<determine_rp_ctxt>) {
|
||||||
|
// mutability is invariant
|
||||||
|
if mt.mutbl == ast::m_mutbl {
|
||||||
|
do cx.with_ambient_variance(rv_invariant) {
|
||||||
|
visitor.visit_ty(mt.ty, cx, visitor);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
visitor.visit_ty(mt.ty, cx, visitor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn determine_rp_in_struct_field(cm: @ast::struct_field,
|
||||||
|
&&cx: determine_rp_ctxt,
|
||||||
|
visitor: visit::vt<determine_rp_ctxt>) {
|
||||||
|
match cm.node.kind {
|
||||||
|
ast::named_field(_, ast::class_mutable, _) => {
|
||||||
|
do cx.with_ambient_variance(rv_invariant) {
|
||||||
|
visit::visit_struct_field(cm, cx, visitor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ast::named_field(_, ast::class_immutable, _) |
|
||||||
|
ast::unnamed_field => {
|
||||||
|
visit::visit_struct_field(cm, cx, visitor);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn determine_rp_in_crate(sess: session,
|
fn determine_rp_in_crate(sess: session,
|
||||||
@@ -582,32 +717,56 @@ fn determine_rp_in_crate(sess: session,
|
|||||||
dep_map: int_hash(),
|
dep_map: int_hash(),
|
||||||
worklist: dvec(),
|
worklist: dvec(),
|
||||||
mut item_id: 0,
|
mut item_id: 0,
|
||||||
mut anon_implies_rp: false});
|
mut anon_implies_rp: false,
|
||||||
|
mut ambient_variance: rv_covariant});
|
||||||
|
|
||||||
// gather up the base set, worklist and dep_map:
|
// Gather up the base set, worklist and dep_map
|
||||||
let visitor = visit::mk_vt(@{
|
let visitor = visit::mk_vt(@{
|
||||||
visit_fn: determine_rp_in_fn,
|
visit_fn: determine_rp_in_fn,
|
||||||
visit_item: determine_rp_in_item,
|
visit_item: determine_rp_in_item,
|
||||||
visit_ty: determine_rp_in_ty,
|
visit_ty: determine_rp_in_ty,
|
||||||
visit_ty_method: determine_rp_in_ty_method,
|
visit_ty_method: determine_rp_in_ty_method,
|
||||||
|
visit_struct_field: determine_rp_in_struct_field,
|
||||||
with *visit::default_visitor()
|
with *visit::default_visitor()
|
||||||
});
|
});
|
||||||
visit::visit_crate(*crate, cx, visitor);
|
visit::visit_crate(*crate, cx, visitor);
|
||||||
|
|
||||||
// propagate indirect dependencies
|
// 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.
|
||||||
while cx.worklist.len() != 0 {
|
while cx.worklist.len() != 0 {
|
||||||
let id = cx.worklist.pop();
|
let c_id = cx.worklist.pop();
|
||||||
debug!{"popped %d from worklist", id};
|
let c_variance = cx.region_paramd_items.get(c_id);
|
||||||
match cx.dep_map.find(id) {
|
debug!["popped %d from worklist", c_id];
|
||||||
|
match cx.dep_map.find(c_id) {
|
||||||
none => {}
|
none => {}
|
||||||
some(vec) => {
|
some(deps) => {
|
||||||
for vec.each |to_id| {
|
for deps.each |dep| {
|
||||||
cx.add_rp(to_id);
|
let v = add_variance(dep.ambient_variance, c_variance);
|
||||||
|
cx.add_rp(dep.id, v);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
debug!("%s", {
|
||||||
|
debug!("Region variance results:");
|
||||||
|
for cx.region_paramd_items.each |key, value| {
|
||||||
|
debug!("item %? (%s) is parameterized with variance %?",
|
||||||
|
key,
|
||||||
|
ast_map::node_id_to_str(ast_map, key,
|
||||||
|
sess.parse_sess.interner),
|
||||||
|
value);
|
||||||
|
}
|
||||||
|
"----"
|
||||||
|
});
|
||||||
|
|
||||||
// return final set
|
// return final set
|
||||||
return cx.region_paramd_items;
|
return cx.region_paramd_items;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2348,7 +2348,7 @@ fn maybe_instantiate_inline(ccx: @crate_ctxt, fn_id: ast::def_id)
|
|||||||
}
|
}
|
||||||
csearch::found(ast::ii_method(impl_did, mth)) => {
|
csearch::found(ast::ii_method(impl_did, mth)) => {
|
||||||
ccx.external.insert(fn_id, some(mth.id));
|
ccx.external.insert(fn_id, some(mth.id));
|
||||||
let {bounds: impl_bnds, rp: _, ty: impl_ty} =
|
let {bounds: impl_bnds, region_param: _, ty: impl_ty} =
|
||||||
ty::lookup_item_type(ccx.tcx, impl_did);
|
ty::lookup_item_type(ccx.tcx, impl_did);
|
||||||
if (*impl_bnds).len() + mth.tps.len() == 0u {
|
if (*impl_bnds).len() + mth.tps.len() == 0u {
|
||||||
let llfn = get_item_val(ccx, mth.id);
|
let llfn = get_item_val(ccx, mth.id);
|
||||||
|
|||||||
@@ -17,6 +17,8 @@ import middle::lint::{get_lint_level, allow};
|
|||||||
import syntax::ast::*;
|
import syntax::ast::*;
|
||||||
import syntax::print::pprust::*;
|
import syntax::print::pprust::*;
|
||||||
import util::ppaux::{ty_to_str, proto_ty_to_str, tys_to_str};
|
import util::ppaux::{ty_to_str, proto_ty_to_str, tys_to_str};
|
||||||
|
import std::serialization::{serialize_option,
|
||||||
|
deserialize_option};
|
||||||
|
|
||||||
export tv_vid, tvi_vid, region_vid, vid;
|
export tv_vid, tvi_vid, region_vid, vid;
|
||||||
export br_hashmap;
|
export br_hashmap;
|
||||||
@@ -181,6 +183,10 @@ export ast_proto_to_proto;
|
|||||||
export is_blockish;
|
export is_blockish;
|
||||||
export method_call_bounds;
|
export method_call_bounds;
|
||||||
export hash_region;
|
export hash_region;
|
||||||
|
export region_variance, rv_covariant, rv_invariant, rv_contravariant;
|
||||||
|
export serialize_region_variance, deserialize_region_variance;
|
||||||
|
export opt_region_variance;
|
||||||
|
export serialize_opt_region_variance, deserialize_opt_region_variance;
|
||||||
|
|
||||||
// Data types
|
// Data types
|
||||||
|
|
||||||
@@ -226,6 +232,12 @@ enum ast_ty_to_ty_cache_entry {
|
|||||||
atttce_resolved(t) /* resolved to a type, irrespective of region */
|
atttce_resolved(t) /* resolved to a type, irrespective of region */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[auto_serialize]
|
||||||
|
type opt_region_variance = option<region_variance>;
|
||||||
|
|
||||||
|
#[auto_serialize]
|
||||||
|
enum region_variance { rv_covariant, rv_invariant, rv_contravariant }
|
||||||
|
|
||||||
// N.B.: Borrows from inlined content are not accurately deserialized. This
|
// N.B.: Borrows from inlined content are not accurately deserialized. This
|
||||||
// is because we don't need the details in trans, we only care if there is an
|
// is because we don't need the details in trans, we only care if there is an
|
||||||
// entry in the table or not.
|
// entry in the table or not.
|
||||||
@@ -565,7 +577,7 @@ fn param_bounds_to_kind(bounds: param_bounds) -> kind {
|
|||||||
/// - `ty`: the base type. May have reference to the (unsubstituted) bound
|
/// - `ty`: the base type. May have reference to the (unsubstituted) bound
|
||||||
/// region `&self` or to (unsubstituted) ty_param types
|
/// region `&self` or to (unsubstituted) ty_param types
|
||||||
type ty_param_bounds_and_ty = {bounds: @~[param_bounds],
|
type ty_param_bounds_and_ty = {bounds: @~[param_bounds],
|
||||||
rp: bool,
|
region_param: option<region_variance>,
|
||||||
ty: t};
|
ty: t};
|
||||||
|
|
||||||
type type_cache = hashmap<ast::def_id, ty_param_bounds_and_ty>;
|
type type_cache = hashmap<ast::def_id, ty_param_bounds_and_ty>;
|
||||||
|
|||||||
@@ -200,7 +200,7 @@ fn lookup_def_ccx(ccx: @crate_ctxt, sp: span, id: ast::node_id) -> ast::def {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn no_params(t: ty::t) -> ty::ty_param_bounds_and_ty {
|
fn no_params(t: ty::t) -> ty::ty_param_bounds_and_ty {
|
||||||
{bounds: @~[], rp: false, ty: t}
|
{bounds: @~[], region_param: none, ty: t}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn require_same_types(
|
fn require_same_types(
|
||||||
|
|||||||
@@ -84,20 +84,20 @@ fn ast_path_to_substs_and_ty<AC: ast_conv, RS: region_scope copy owned>(
|
|||||||
path: @ast::path) -> ty_param_substs_and_ty {
|
path: @ast::path) -> ty_param_substs_and_ty {
|
||||||
|
|
||||||
let tcx = self.tcx();
|
let tcx = self.tcx();
|
||||||
let {bounds: decl_bounds, rp: decl_rp, ty: decl_ty} =
|
let {bounds: decl_bounds, region_param: decl_rp, ty: decl_ty} =
|
||||||
self.get_item_ty(did);
|
self.get_item_ty(did);
|
||||||
|
|
||||||
debug!{"ast_path_to_substs_and_ty: did=%? decl_rp=%b",
|
debug!["ast_path_to_substs_and_ty: did=%? decl_rp=%?",
|
||||||
did, decl_rp};
|
did, decl_rp];
|
||||||
|
|
||||||
// If the type is parameterized by the self region, then replace self
|
// If the type is parameterized by the self region, then replace self
|
||||||
// region with the current anon region binding (in other words,
|
// region with the current anon region binding (in other words,
|
||||||
// whatever & would get replaced with).
|
// whatever & would get replaced with).
|
||||||
let self_r = match (decl_rp, path.rp) {
|
let self_r = match (decl_rp, path.rp) {
|
||||||
(false, none) => {
|
(none, none) => {
|
||||||
none
|
none
|
||||||
}
|
}
|
||||||
(false, some(_)) => {
|
(none, some(_)) => {
|
||||||
tcx.sess.span_err(
|
tcx.sess.span_err(
|
||||||
path.span,
|
path.span,
|
||||||
fmt!{"no region bound is allowed on `%s`, \
|
fmt!{"no region bound is allowed on `%s`, \
|
||||||
@@ -105,12 +105,12 @@ fn ast_path_to_substs_and_ty<AC: ast_conv, RS: region_scope copy owned>(
|
|||||||
ty::item_path_str(tcx, did)});
|
ty::item_path_str(tcx, did)});
|
||||||
none
|
none
|
||||||
}
|
}
|
||||||
(true, none) => {
|
(some(_), none) => {
|
||||||
let res = rscope.anon_region(path.span);
|
let res = rscope.anon_region(path.span);
|
||||||
let r = get_region_reporting_err(self.tcx(), path.span, res);
|
let r = get_region_reporting_err(self.tcx(), path.span, res);
|
||||||
some(r)
|
some(r)
|
||||||
}
|
}
|
||||||
(true, some(r)) => {
|
(some(_), some(r)) => {
|
||||||
some(ast_region_to_region(self, rscope, path.span, r))
|
some(ast_region_to_region(self, rscope, path.span, r))
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -71,7 +71,8 @@ import astconv::{ast_region_to_region};
|
|||||||
import middle::ty::{tv_vid, vid};
|
import middle::ty::{tv_vid, vid};
|
||||||
import regionmanip::{replace_bound_regions_in_fn_ty};
|
import regionmanip::{replace_bound_regions_in_fn_ty};
|
||||||
import rscope::{anon_rscope, binding_rscope, empty_rscope, in_anon_rscope};
|
import rscope::{anon_rscope, binding_rscope, empty_rscope, in_anon_rscope};
|
||||||
import rscope::{in_binding_rscope, region_scope, type_rscope};
|
import rscope::{in_binding_rscope, region_scope, type_rscope,
|
||||||
|
bound_self_region};
|
||||||
import syntax::ast::ty_i;
|
import syntax::ast::ty_i;
|
||||||
import typeck::infer::{resolve_type, force_tvar};
|
import typeck::infer::{resolve_type, force_tvar};
|
||||||
|
|
||||||
@@ -84,17 +85,17 @@ type self_info = {
|
|||||||
explicit_self: ast::self_ty
|
explicit_self: ast::self_ty
|
||||||
};
|
};
|
||||||
|
|
||||||
type fn_ctxt_ =
|
struct fn_ctxt {
|
||||||
// var_bindings, locals and next_var_id are shared
|
// var_bindings, locals and next_var_id are shared
|
||||||
// with any nested functions that capture the environment
|
// with any nested functions that capture the environment
|
||||||
// (and with any functions whose environment is being captured).
|
// (and with any functions whose environment is being captured).
|
||||||
{self_impl_def_id: option<ast::def_id>,
|
self_impl_def_id: option<ast::def_id>;
|
||||||
ret_ty: ty::t,
|
ret_ty: ty::t;
|
||||||
// Used by loop bodies that return from the outer function
|
// Used by loop bodies that return from the outer function
|
||||||
indirect_ret_ty: option<ty::t>,
|
indirect_ret_ty: option<ty::t>;
|
||||||
purity: ast::purity,
|
purity: ast::purity;
|
||||||
infcx: infer::infer_ctxt,
|
infcx: infer::infer_ctxt;
|
||||||
locals: hashmap<ast::node_id, tv_vid>,
|
locals: hashmap<ast::node_id, tv_vid>;
|
||||||
|
|
||||||
// Sometimes we generate region pointers where the precise region
|
// Sometimes we generate region pointers where the precise region
|
||||||
// to use is not known. For example, an expression like `&x.f`
|
// to use is not known. For example, an expression like `&x.f`
|
||||||
@@ -109,17 +110,14 @@ type fn_ctxt_ =
|
|||||||
// inference selects the ultimate value. Finally, borrowck is
|
// inference selects the ultimate value. Finally, borrowck is
|
||||||
// charged with guaranteeing that the value whose address was taken
|
// charged with guaranteeing that the value whose address was taken
|
||||||
// can actually be made to live as long as it needs to live.
|
// can actually be made to live as long as it needs to live.
|
||||||
mut region_lb: ast::node_id,
|
mut region_lb: ast::node_id;
|
||||||
|
|
||||||
in_scope_regions: isr_alist,
|
in_scope_regions: isr_alist;
|
||||||
|
|
||||||
node_types: hashmap<ast::node_id, ty::t>,
|
node_types: hashmap<ast::node_id, ty::t>;
|
||||||
node_type_substs: hashmap<ast::node_id, ty::substs>,
|
node_type_substs: hashmap<ast::node_id, ty::substs>;
|
||||||
|
|
||||||
ccx: @crate_ctxt};
|
ccx: @crate_ctxt;
|
||||||
|
|
||||||
enum fn_ctxt {
|
|
||||||
fn_ctxt_(fn_ctxt_)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Used by check_const and check_enum_variants
|
// Used by check_const and check_enum_variants
|
||||||
@@ -127,7 +125,8 @@ fn blank_fn_ctxt(ccx: @crate_ctxt, rty: ty::t,
|
|||||||
region_bnd: ast::node_id) -> @fn_ctxt {
|
region_bnd: ast::node_id) -> @fn_ctxt {
|
||||||
// It's kind of a kludge to manufacture a fake function context
|
// 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
|
// and statement context, but we might as well do write the code only once
|
||||||
@fn_ctxt_({self_impl_def_id: none,
|
@fn_ctxt {
|
||||||
|
self_impl_def_id: none,
|
||||||
ret_ty: rty,
|
ret_ty: rty,
|
||||||
indirect_ret_ty: none,
|
indirect_ret_ty: none,
|
||||||
purity: ast::pure_fn,
|
purity: ast::pure_fn,
|
||||||
@@ -137,7 +136,8 @@ fn blank_fn_ctxt(ccx: @crate_ctxt, rty: ty::t,
|
|||||||
in_scope_regions: @nil,
|
in_scope_regions: @nil,
|
||||||
node_types: map::int_hash(),
|
node_types: map::int_hash(),
|
||||||
node_type_substs: map::int_hash(),
|
node_type_substs: map::int_hash(),
|
||||||
ccx: ccx})
|
ccx: ccx
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// a list of mapping from in-scope-region-names ("isr") to the
|
// a list of mapping from in-scope-region-names ("isr") to the
|
||||||
@@ -245,7 +245,8 @@ fn check_fn(ccx: @crate_ctxt,
|
|||||||
}
|
}
|
||||||
} else { none };
|
} else { none };
|
||||||
|
|
||||||
@fn_ctxt_({self_impl_def_id: self_info.map(|info| info.def_id),
|
@fn_ctxt {
|
||||||
|
self_impl_def_id: self_info.map(|info| info.def_id),
|
||||||
ret_ty: ret_ty,
|
ret_ty: ret_ty,
|
||||||
indirect_ret_ty: indirect_ret_ty,
|
indirect_ret_ty: indirect_ret_ty,
|
||||||
purity: purity,
|
purity: purity,
|
||||||
@@ -255,7 +256,8 @@ fn check_fn(ccx: @crate_ctxt,
|
|||||||
in_scope_regions: isr,
|
in_scope_regions: isr,
|
||||||
node_types: node_types,
|
node_types: node_types,
|
||||||
node_type_substs: node_type_substs,
|
node_type_substs: node_type_substs,
|
||||||
ccx: ccx})
|
ccx: ccx
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Update the self_info to contain an accurate self type (taking
|
// Update the self_info to contain an accurate self type (taking
|
||||||
@@ -478,9 +480,9 @@ fn check_item(ccx: @crate_ctxt, it: @ast::item) {
|
|||||||
check_bare_fn(ccx, decl, body, it.id, none);
|
check_bare_fn(ccx, decl, body, it.id, none);
|
||||||
}
|
}
|
||||||
ast::item_impl(tps, _, ty, ms) => {
|
ast::item_impl(tps, _, ty, ms) => {
|
||||||
let rp = ccx.tcx.region_paramd_items.contains_key(it.id);
|
let rp = ccx.tcx.region_paramd_items.find(it.id);
|
||||||
debug!{"item_impl %s with id %d rp %b",
|
debug!("item_impl %s with id %d rp %?",
|
||||||
ccx.tcx.sess.str_of(it.ident), it.id, rp};
|
ccx.tcx.sess.str_of(it.ident), it.id, rp);
|
||||||
let self_ty = ccx.to_ty(rscope::type_rscope(rp), ty);
|
let self_ty = ccx.to_ty(rscope::type_rscope(rp), ty);
|
||||||
for ms.each |m| {
|
for ms.each |m| {
|
||||||
check_method(ccx, m, self_ty, local_def(it.id));
|
check_method(ccx, m, self_ty, local_def(it.id));
|
||||||
@@ -701,6 +703,15 @@ impl @fn_ctxt {
|
|||||||
self.region_lb = old_region_lb;
|
self.region_lb = old_region_lb;
|
||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn region_var_if_parameterized(rp: option<ty::region_variance>,
|
||||||
|
span: span)
|
||||||
|
-> option<ty::region> {
|
||||||
|
match rp {
|
||||||
|
some(_) => some(self.infcx.next_region_var_nb(span)),
|
||||||
|
none => none
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn do_autoderef(fcx: @fn_ctxt, sp: span, t: ty::t) -> ty::t {
|
fn do_autoderef(fcx: @fn_ctxt, sp: span, t: ty::t) -> ty::t {
|
||||||
@@ -789,14 +800,14 @@ fn impl_self_ty(fcx: @fn_ctxt,
|
|||||||
require_rp: bool) -> ty_param_substs_and_ty {
|
require_rp: bool) -> ty_param_substs_and_ty {
|
||||||
let tcx = fcx.ccx.tcx;
|
let tcx = fcx.ccx.tcx;
|
||||||
|
|
||||||
let {n_tps, rp, raw_ty} = if did.crate == ast::local_crate {
|
let {n_tps, region_param, raw_ty} = if did.crate == ast::local_crate {
|
||||||
let rp = fcx.tcx().region_paramd_items.contains_key(did.node);
|
let region_param = fcx.tcx().region_paramd_items.find(did.node);
|
||||||
match check tcx.items.find(did.node) {
|
match check tcx.items.find(did.node) {
|
||||||
some(ast_map::node_item(@{node: ast::item_impl(ts, _, st, _),
|
some(ast_map::node_item(@{node: ast::item_impl(ts, _, st, _),
|
||||||
_}, _)) => {
|
_}, _)) => {
|
||||||
{n_tps: ts.len(),
|
{n_tps: ts.len(),
|
||||||
rp: rp,
|
region_param: region_param,
|
||||||
raw_ty: fcx.ccx.to_ty(rscope::type_rscope(rp), st)}
|
raw_ty: fcx.ccx.to_ty(rscope::type_rscope(region_param), st)}
|
||||||
}
|
}
|
||||||
some(ast_map::node_item(@{node: ast::item_class(_, ts),
|
some(ast_map::node_item(@{node: ast::item_class(_, ts),
|
||||||
id: class_id, _},_)) => {
|
id: class_id, _},_)) => {
|
||||||
@@ -805,10 +816,9 @@ fn impl_self_ty(fcx: @fn_ctxt,
|
|||||||
we substitute in fresh vars for them)
|
we substitute in fresh vars for them)
|
||||||
*/
|
*/
|
||||||
{n_tps: ts.len(),
|
{n_tps: ts.len(),
|
||||||
rp: rp,
|
region_param: region_param,
|
||||||
raw_ty: ty::mk_class(tcx, local_def(class_id),
|
raw_ty: ty::mk_class(tcx, local_def(class_id),
|
||||||
{self_r: if rp {some(ty::re_bound(ty::br_self))}
|
{self_r: rscope::bound_self_region(region_param),
|
||||||
else {none},
|
|
||||||
self_ty: none,
|
self_ty: none,
|
||||||
tps: ty::ty_params_to_tys(tcx, ts)})}
|
tps: ty::ty_params_to_tys(tcx, ts)})}
|
||||||
}
|
}
|
||||||
@@ -818,13 +828,15 @@ fn impl_self_ty(fcx: @fn_ctxt,
|
|||||||
} else {
|
} else {
|
||||||
let ity = ty::lookup_item_type(tcx, did);
|
let ity = ty::lookup_item_type(tcx, did);
|
||||||
{n_tps: vec::len(*ity.bounds),
|
{n_tps: vec::len(*ity.bounds),
|
||||||
rp: ity.rp,
|
region_param: ity.region_param,
|
||||||
raw_ty: ity.ty}
|
raw_ty: ity.ty}
|
||||||
};
|
};
|
||||||
|
|
||||||
let rp = rp || require_rp;
|
let self_r = if region_param.is_some() || require_rp {
|
||||||
let self_r = if rp {some(fcx.infcx.next_region_var(expr.span, expr.id))}
|
some(fcx.infcx.next_region_var(expr.span, expr.id))
|
||||||
else {none};
|
} else {
|
||||||
|
none
|
||||||
|
};
|
||||||
let tps = fcx.infcx.next_ty_vars(n_tps);
|
let tps = fcx.infcx.next_ty_vars(n_tps);
|
||||||
|
|
||||||
let substs = {self_r: self_r, self_ty: none, tps: tps};
|
let substs = {self_r: self_r, self_ty: none, tps: tps};
|
||||||
@@ -1832,7 +1844,7 @@ fn check_expr_with_unifier(fcx: @fn_ctxt,
|
|||||||
let type_parameter_count, region_parameterized, raw_type;
|
let type_parameter_count, region_parameterized, raw_type;
|
||||||
if class_id.crate == ast::local_crate {
|
if class_id.crate == ast::local_crate {
|
||||||
region_parameterized =
|
region_parameterized =
|
||||||
tcx.region_paramd_items.contains_key(class_id.node);
|
tcx.region_paramd_items.find(class_id.node);
|
||||||
match tcx.items.find(class_id.node) {
|
match tcx.items.find(class_id.node) {
|
||||||
some(ast_map::node_item(@{
|
some(ast_map::node_item(@{
|
||||||
node: ast::item_class(_, type_parameters),
|
node: ast::item_class(_, type_parameters),
|
||||||
@@ -1841,12 +1853,8 @@ fn check_expr_with_unifier(fcx: @fn_ctxt,
|
|||||||
|
|
||||||
type_parameter_count = type_parameters.len();
|
type_parameter_count = type_parameters.len();
|
||||||
|
|
||||||
let self_region;
|
let self_region =
|
||||||
if region_parameterized {
|
bound_self_region(region_parameterized);
|
||||||
self_region = some(ty::re_bound(ty::br_self));
|
|
||||||
} else {
|
|
||||||
self_region = none;
|
|
||||||
}
|
|
||||||
|
|
||||||
raw_type = ty::mk_class(tcx, class_id, {
|
raw_type = ty::mk_class(tcx, class_id, {
|
||||||
self_r: self_region,
|
self_r: self_region,
|
||||||
@@ -1862,18 +1870,14 @@ fn check_expr_with_unifier(fcx: @fn_ctxt,
|
|||||||
} else {
|
} else {
|
||||||
let item_type = ty::lookup_item_type(tcx, class_id);
|
let item_type = ty::lookup_item_type(tcx, class_id);
|
||||||
type_parameter_count = (*item_type.bounds).len();
|
type_parameter_count = (*item_type.bounds).len();
|
||||||
region_parameterized = item_type.rp;
|
region_parameterized = item_type.region_param;
|
||||||
raw_type = item_type.ty;
|
raw_type = item_type.ty;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generate the struct type.
|
// Generate the struct type.
|
||||||
let self_region;
|
let self_region =
|
||||||
if region_parameterized {
|
fcx.region_var_if_parameterized(region_parameterized,
|
||||||
self_region = some(fcx.infcx.next_region_var(expr.span, expr.id));
|
expr.span);
|
||||||
} else {
|
|
||||||
self_region = none;
|
|
||||||
}
|
|
||||||
|
|
||||||
let type_parameters = fcx.infcx.next_ty_vars(type_parameter_count);
|
let type_parameters = fcx.infcx.next_ty_vars(type_parameter_count);
|
||||||
let substitutions = {
|
let substitutions = {
|
||||||
self_r: self_region,
|
self_r: self_region,
|
||||||
@@ -2082,8 +2086,8 @@ fn check_block_no_value(fcx: @fn_ctxt, blk: ast::blk) -> bool {
|
|||||||
|
|
||||||
fn check_block(fcx0: @fn_ctxt, blk: ast::blk) -> bool {
|
fn check_block(fcx0: @fn_ctxt, blk: ast::blk) -> bool {
|
||||||
let fcx = match blk.node.rules {
|
let fcx = match blk.node.rules {
|
||||||
ast::unchecked_blk => @fn_ctxt_({purity: ast::impure_fn with **fcx0}),
|
ast::unchecked_blk => @fn_ctxt {purity: ast::impure_fn with *fcx0},
|
||||||
ast::unsafe_blk => @fn_ctxt_({purity: ast::unsafe_fn with **fcx0}),
|
ast::unsafe_blk => @fn_ctxt {purity: ast::unsafe_fn with *fcx0},
|
||||||
ast::default_blk => fcx0
|
ast::default_blk => fcx0
|
||||||
};
|
};
|
||||||
do fcx.with_region_lb(blk.node.id) {
|
do fcx.with_region_lb(blk.node.id) {
|
||||||
@@ -2294,7 +2298,7 @@ fn ty_param_bounds_and_ty_for_def(fcx: @fn_ctxt, sp: span, defn: ast::def) ->
|
|||||||
// extern functions are just u8 pointers
|
// extern functions are just u8 pointers
|
||||||
return {
|
return {
|
||||||
bounds: @~[],
|
bounds: @~[],
|
||||||
rp: false,
|
region_param: none,
|
||||||
ty: ty::mk_ptr(
|
ty: ty::mk_ptr(
|
||||||
fcx.ccx.tcx,
|
fcx.ccx.tcx,
|
||||||
{
|
{
|
||||||
@@ -2358,19 +2362,21 @@ fn instantiate_path(fcx: @fn_ctxt,
|
|||||||
// determine the region bound, using the value given by the user
|
// determine the region bound, using the value given by the user
|
||||||
// (if any) and otherwise using a fresh region variable
|
// (if any) and otherwise using a fresh region variable
|
||||||
let self_r = match pth.rp {
|
let self_r = match pth.rp {
|
||||||
some(r) if !tpt.rp => {
|
some(r) => {
|
||||||
|
match tpt.region_param {
|
||||||
|
none => {
|
||||||
fcx.ccx.tcx.sess.span_err
|
fcx.ccx.tcx.sess.span_err
|
||||||
(span, ~"this item is not region-parameterized");
|
(span, ~"this item is not region-parameterized");
|
||||||
none
|
none
|
||||||
}
|
}
|
||||||
some(r) => {
|
some(_) => {
|
||||||
some(ast_region_to_region(fcx, fcx, span, r))
|
some(ast_region_to_region(fcx, fcx, span, r))
|
||||||
}
|
}
|
||||||
none if tpt.rp => {
|
}
|
||||||
some(fcx.infcx.next_region_var_with_lb(span, region_lb))
|
|
||||||
}
|
}
|
||||||
none => {
|
none => {
|
||||||
none
|
fcx.region_var_if_parameterized(
|
||||||
|
tpt.region_param, span)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -402,11 +402,9 @@ struct CoherenceChecker {
|
|||||||
|
|
||||||
fn universally_quantify_polytype(polytype: ty_param_bounds_and_ty) -> t {
|
fn universally_quantify_polytype(polytype: ty_param_bounds_and_ty) -> t {
|
||||||
// NDM--this span is bogus.
|
// NDM--this span is bogus.
|
||||||
let self_region = if !polytype.rp {
|
let self_region =
|
||||||
none
|
polytype.region_param.map(
|
||||||
} else {
|
|_r| self.inference_context.next_region_var_nb(dummy_sp()));
|
||||||
some(self.inference_context.next_region_var_nb(dummy_sp()))
|
|
||||||
};
|
|
||||||
|
|
||||||
let bounds_count = polytype.bounds.len();
|
let bounds_count = polytype.bounds.len();
|
||||||
let type_parameters =
|
let type_parameters =
|
||||||
|
|||||||
@@ -112,7 +112,7 @@ fn get_enum_variant_types(ccx: @crate_ctxt,
|
|||||||
enum_ty: ty::t,
|
enum_ty: ty::t,
|
||||||
variants: ~[ast::variant],
|
variants: ~[ast::variant],
|
||||||
ty_params: ~[ast::ty_param],
|
ty_params: ~[ast::ty_param],
|
||||||
rp: bool) {
|
rp: option<ty::region_variance>) {
|
||||||
let tcx = ccx.tcx;
|
let tcx = ccx.tcx;
|
||||||
|
|
||||||
// Create a set of parameter types shared among all the variants.
|
// Create a set of parameter types shared among all the variants.
|
||||||
@@ -150,7 +150,7 @@ fn get_enum_variant_types(ccx: @crate_ctxt,
|
|||||||
none => {}
|
none => {}
|
||||||
some(result_ty) => {
|
some(result_ty) => {
|
||||||
let tpt = {bounds: ty_param_bounds(ccx, ty_params),
|
let tpt = {bounds: ty_param_bounds(ccx, ty_params),
|
||||||
rp: rp,
|
region_param: rp,
|
||||||
ty: result_ty};
|
ty: result_ty};
|
||||||
tcx.tcache.insert(local_def(variant.node.id), tpt);
|
tcx.tcache.insert(local_def(variant.node.id), tpt);
|
||||||
write_ty_to_tcx(tcx, variant.node.id, result_ty);
|
write_ty_to_tcx(tcx, variant.node.id, result_ty);
|
||||||
@@ -167,7 +167,8 @@ fn ensure_trait_methods(ccx: @crate_ctxt, id: ast::node_id, trait_ty: ty::t) {
|
|||||||
|
|
||||||
fn make_static_method_ty(ccx: @crate_ctxt,
|
fn make_static_method_ty(ccx: @crate_ctxt,
|
||||||
am: ast::ty_method,
|
am: ast::ty_method,
|
||||||
rp: bool, m: ty::method,
|
rp: option<ty::region_variance>,
|
||||||
|
m: ty::method,
|
||||||
// Take this as an argument b/c we may check
|
// Take this as an argument b/c we may check
|
||||||
// the impl before the trait.
|
// the impl before the trait.
|
||||||
trait_ty: ty::t,
|
trait_ty: ty::t,
|
||||||
@@ -197,20 +198,22 @@ fn ensure_trait_methods(ccx: @crate_ctxt, id: ast::node_id, trait_ty: ty::t) {
|
|||||||
let bounds = @(*trait_bounds + ~[@~[ty::bound_trait(trait_ty)]]
|
let bounds = @(*trait_bounds + ~[@~[ty::bound_trait(trait_ty)]]
|
||||||
+ *m.tps);
|
+ *m.tps);
|
||||||
ccx.tcx.tcache.insert(local_def(am.id),
|
ccx.tcx.tcache.insert(local_def(am.id),
|
||||||
{bounds: bounds, rp: rp, ty: ty});
|
{bounds: bounds,
|
||||||
|
region_param: rp,
|
||||||
|
ty: ty});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
let tcx = ccx.tcx;
|
let tcx = ccx.tcx;
|
||||||
let rp = tcx.region_paramd_items.contains_key(id);
|
let region_paramd = tcx.region_paramd_items.find(id);
|
||||||
match tcx.items.get(id) {
|
match tcx.items.get(id) {
|
||||||
ast_map::node_item(@{node: ast::item_trait(params, _, ms), _}, _) => {
|
ast_map::node_item(@{node: ast::item_trait(params, _, ms), _}, _) => {
|
||||||
store_methods::<ast::trait_method>(ccx, id, ms, |m| {
|
store_methods::<ast::trait_method>(ccx, id, ms, |m| {
|
||||||
let trait_bounds = ty_param_bounds(ccx, params);
|
let trait_bounds = ty_param_bounds(ccx, params);
|
||||||
let ty_m = trait_method_to_ty_method(m);
|
let ty_m = trait_method_to_ty_method(m);
|
||||||
let method_ty = ty_of_ty_method(ccx, ty_m, rp);
|
let method_ty = ty_of_ty_method(ccx, ty_m, region_paramd);
|
||||||
if ty_m.self_ty.node == ast::sty_static {
|
if ty_m.self_ty.node == ast::sty_static {
|
||||||
make_static_method_ty(ccx, ty_m, rp,
|
make_static_method_ty(ccx, ty_m, region_paramd,
|
||||||
method_ty, trait_ty, trait_bounds);
|
method_ty, trait_ty, trait_bounds);
|
||||||
}
|
}
|
||||||
method_ty
|
method_ty
|
||||||
@@ -220,7 +223,7 @@ fn ensure_trait_methods(ccx: @crate_ctxt, id: ast::node_id, trait_ty: ty::t) {
|
|||||||
// All methods need to be stored, since lookup_method
|
// All methods need to be stored, since lookup_method
|
||||||
// relies on the same method cache for self-calls
|
// relies on the same method cache for self-calls
|
||||||
store_methods::<@ast::method>(ccx, id, struct_def.methods, |m| {
|
store_methods::<@ast::method>(ccx, id, struct_def.methods, |m| {
|
||||||
ty_of_method(ccx, m, rp)
|
ty_of_method(ccx, m, region_paramd)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
_ => { /* Ignore things that aren't traits or classes */ }
|
_ => { /* Ignore things that aren't traits or classes */ }
|
||||||
@@ -316,7 +319,7 @@ fn compare_impl_method(tcx: ty::ctxt, sp: span,
|
|||||||
|
|
||||||
fn check_methods_against_trait(ccx: @crate_ctxt,
|
fn check_methods_against_trait(ccx: @crate_ctxt,
|
||||||
tps: ~[ast::ty_param],
|
tps: ~[ast::ty_param],
|
||||||
rp: bool,
|
rp: option<ty::region_variance>,
|
||||||
selfty: ty::t,
|
selfty: ty::t,
|
||||||
a_trait_ty: @ast::trait_ref,
|
a_trait_ty: @ast::trait_ref,
|
||||||
impl_ms: ~[converted_method]) {
|
impl_ms: ~[converted_method]) {
|
||||||
@@ -370,21 +373,23 @@ fn check_methods_against_trait(ccx: @crate_ctxt,
|
|||||||
} // fn
|
} // fn
|
||||||
|
|
||||||
fn convert_field(ccx: @crate_ctxt,
|
fn convert_field(ccx: @crate_ctxt,
|
||||||
rp: bool,
|
rp: option<ty::region_variance>,
|
||||||
bounds: @~[ty::param_bounds],
|
bounds: @~[ty::param_bounds],
|
||||||
v: @ast::struct_field) {
|
v: @ast::struct_field) {
|
||||||
let tt = ccx.to_ty(type_rscope(rp), v.node.ty);
|
let tt = ccx.to_ty(type_rscope(rp), v.node.ty);
|
||||||
write_ty_to_tcx(ccx.tcx, v.node.id, tt);
|
write_ty_to_tcx(ccx.tcx, v.node.id, tt);
|
||||||
/* add the field to the tcache */
|
/* add the field to the tcache */
|
||||||
ccx.tcx.tcache.insert(local_def(v.node.id),
|
ccx.tcx.tcache.insert(local_def(v.node.id),
|
||||||
{bounds: bounds, rp: rp, ty: tt});
|
{bounds: bounds,
|
||||||
|
region_param: rp,
|
||||||
|
ty: tt});
|
||||||
}
|
}
|
||||||
|
|
||||||
type converted_method = {mty: ty::method, id: ast::node_id, span: span};
|
type converted_method = {mty: ty::method, id: ast::node_id, span: span};
|
||||||
|
|
||||||
fn convert_methods(ccx: @crate_ctxt,
|
fn convert_methods(ccx: @crate_ctxt,
|
||||||
ms: ~[@ast::method],
|
ms: ~[@ast::method],
|
||||||
rp: bool,
|
rp: option<ty::region_variance>,
|
||||||
rcvr_bounds: @~[ty::param_bounds]) -> ~[converted_method] {
|
rcvr_bounds: @~[ty::param_bounds]) -> ~[converted_method] {
|
||||||
|
|
||||||
let tcx = ccx.tcx;
|
let tcx = ccx.tcx;
|
||||||
@@ -397,7 +402,9 @@ fn convert_methods(ccx: @crate_ctxt,
|
|||||||
|
|
||||||
// n.b.: the type of a method is parameterized by both
|
// n.b.: the type of a method is parameterized by both
|
||||||
// the tps on the receiver and those on the method itself
|
// the tps on the receiver and those on the method itself
|
||||||
{bounds: @(vec::append(*rcvr_bounds, *bounds)), rp: rp, ty: fty});
|
{bounds: @(vec::append(*rcvr_bounds, *bounds)),
|
||||||
|
region_param: rp,
|
||||||
|
ty: fty});
|
||||||
write_ty_to_tcx(tcx, m.id, fty);
|
write_ty_to_tcx(tcx, m.id, fty);
|
||||||
{mty: mty, id: m.id, span: m.span}
|
{mty: mty, id: m.id, span: m.span}
|
||||||
}
|
}
|
||||||
@@ -405,9 +412,9 @@ fn convert_methods(ccx: @crate_ctxt,
|
|||||||
|
|
||||||
fn convert(ccx: @crate_ctxt, it: @ast::item) {
|
fn convert(ccx: @crate_ctxt, it: @ast::item) {
|
||||||
let tcx = ccx.tcx;
|
let tcx = ccx.tcx;
|
||||||
let rp = tcx.region_paramd_items.contains_key(it.id);
|
let rp = tcx.region_paramd_items.find(it.id);
|
||||||
debug!{"convert: item %s with id %d rp %b", tcx.sess.str_of(it.ident),
|
#debug["convert: item %s with id %d rp %?",
|
||||||
it.id, rp};
|
tcx.sess.str_of(it.ident), it.id, rp];
|
||||||
match it.node {
|
match it.node {
|
||||||
// These don't define types.
|
// These don't define types.
|
||||||
ast::item_foreign_mod(_) | ast::item_mod(_) => {}
|
ast::item_foreign_mod(_) | ast::item_mod(_) => {}
|
||||||
@@ -423,7 +430,7 @@ fn convert(ccx: @crate_ctxt, it: @ast::item) {
|
|||||||
write_ty_to_tcx(tcx, it.id, selfty);
|
write_ty_to_tcx(tcx, it.id, selfty);
|
||||||
tcx.tcache.insert(local_def(it.id),
|
tcx.tcache.insert(local_def(it.id),
|
||||||
{bounds: i_bounds,
|
{bounds: i_bounds,
|
||||||
rp: rp,
|
region_param: rp,
|
||||||
ty: selfty});
|
ty: selfty});
|
||||||
|
|
||||||
let cms = convert_methods(ccx, ms, rp, i_bounds);
|
let cms = convert_methods(ccx, ms, rp, i_bounds);
|
||||||
@@ -465,8 +472,11 @@ fn convert(ccx: @crate_ctxt, it: @ast::item) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn convert_struct(ccx: @crate_ctxt, rp: bool, struct_def: @ast::struct_def,
|
fn convert_struct(ccx: @crate_ctxt,
|
||||||
tps: ~[ast::ty_param], tpt: ty::ty_param_bounds_and_ty,
|
rp: option<ty::region_variance>,
|
||||||
|
struct_def: @ast::struct_def,
|
||||||
|
tps: ~[ast::ty_param],
|
||||||
|
tpt: ty::ty_param_bounds_and_ty,
|
||||||
id: ast::node_id) {
|
id: ast::node_id) {
|
||||||
let tcx = ccx.tcx;
|
let tcx = ccx.tcx;
|
||||||
do option::iter(struct_def.ctor) |ctor| {
|
do option::iter(struct_def.ctor) |ctor| {
|
||||||
@@ -475,7 +485,7 @@ fn convert_struct(ccx: @crate_ctxt, rp: bool, struct_def: @ast::struct_def,
|
|||||||
|a| ty_of_arg(ccx, type_rscope(rp), a, none) );
|
|a| ty_of_arg(ccx, type_rscope(rp), a, none) );
|
||||||
let t_res = ty::mk_class(
|
let t_res = ty::mk_class(
|
||||||
tcx, local_def(id),
|
tcx, local_def(id),
|
||||||
{self_r: if rp {some(ty::re_bound(ty::br_self))} else {none},
|
{self_r: rscope::bound_self_region(rp),
|
||||||
self_ty: none,
|
self_ty: none,
|
||||||
tps: ty::ty_params_to_tys(tcx, tps)});
|
tps: ty::ty_params_to_tys(tcx, tps)});
|
||||||
let t_ctor = ty::mk_fn(
|
let t_ctor = ty::mk_fn(
|
||||||
@@ -488,7 +498,7 @@ fn convert_struct(ccx: @crate_ctxt, rp: bool, struct_def: @ast::struct_def,
|
|||||||
write_ty_to_tcx(tcx, ctor.node.id, t_ctor);
|
write_ty_to_tcx(tcx, ctor.node.id, t_ctor);
|
||||||
tcx.tcache.insert(local_def(ctor.node.id),
|
tcx.tcache.insert(local_def(ctor.node.id),
|
||||||
{bounds: tpt.bounds,
|
{bounds: tpt.bounds,
|
||||||
rp: rp,
|
region_param: rp,
|
||||||
ty: t_ctor});
|
ty: t_ctor});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -501,7 +511,7 @@ fn convert_struct(ccx: @crate_ctxt, rp: bool, struct_def: @ast::struct_def,
|
|||||||
write_ty_to_tcx(tcx, dtor.node.id, t_dtor);
|
write_ty_to_tcx(tcx, dtor.node.id, t_dtor);
|
||||||
tcx.tcache.insert(local_def(dtor.node.id),
|
tcx.tcache.insert(local_def(dtor.node.id),
|
||||||
{bounds: tpt.bounds,
|
{bounds: tpt.bounds,
|
||||||
rp: rp,
|
region_param: rp,
|
||||||
ty: t_dtor});
|
ty: t_dtor});
|
||||||
};
|
};
|
||||||
ensure_trait_methods(ccx, id, tpt.ty);
|
ensure_trait_methods(ccx, id, tpt.ty);
|
||||||
@@ -536,8 +546,7 @@ fn convert_foreign(ccx: @crate_ctxt, i: @ast::foreign_item) {
|
|||||||
|
|
||||||
fn ty_of_method(ccx: @crate_ctxt,
|
fn ty_of_method(ccx: @crate_ctxt,
|
||||||
m: @ast::method,
|
m: @ast::method,
|
||||||
rp: bool) -> ty::method {
|
rp: option<ty::region_variance>) -> ty::method {
|
||||||
// XXX: Are the bounds correct here?
|
|
||||||
{ident: m.ident,
|
{ident: m.ident,
|
||||||
tps: ty_param_bounds(ccx, m.tps),
|
tps: ty_param_bounds(ccx, m.tps),
|
||||||
fty: ty_of_fn_decl(ccx, type_rscope(rp), ast::proto_bare, @~[],
|
fty: ty_of_fn_decl(ccx, type_rscope(rp), ast::proto_bare, @~[],
|
||||||
@@ -549,7 +558,7 @@ fn ty_of_method(ccx: @crate_ctxt,
|
|||||||
|
|
||||||
fn ty_of_ty_method(self: @crate_ctxt,
|
fn ty_of_ty_method(self: @crate_ctxt,
|
||||||
m: ast::ty_method,
|
m: ast::ty_method,
|
||||||
rp: bool) -> ty::method {
|
rp: option<ty::region_variance>) -> ty::method {
|
||||||
{ident: m.ident,
|
{ident: m.ident,
|
||||||
tps: ty_param_bounds(self, m.tps),
|
tps: ty_param_bounds(self, m.tps),
|
||||||
fty: ty_of_fn_decl(self, type_rscope(rp), ast::proto_bare, @~[], m.decl,
|
fty: ty_of_fn_decl(self, type_rscope(rp), ast::proto_bare, @~[], m.decl,
|
||||||
@@ -564,7 +573,8 @@ fn ty_of_ty_method(self: @crate_ctxt,
|
|||||||
it's bound to a valid trait type. Returns the def_id for the defining
|
it's bound to a valid trait type. Returns the def_id for the defining
|
||||||
trait. Fails if the type is a type other than an trait type.
|
trait. Fails if the type is a type other than an trait type.
|
||||||
*/
|
*/
|
||||||
fn instantiate_trait_ref(ccx: @crate_ctxt, t: @ast::trait_ref, rp: bool)
|
fn instantiate_trait_ref(ccx: @crate_ctxt, t: @ast::trait_ref,
|
||||||
|
rp: option<ty::region_variance>)
|
||||||
-> (ast::def_id, ty_param_substs_and_ty) {
|
-> (ast::def_id, ty_param_substs_and_ty) {
|
||||||
|
|
||||||
let sp = t.path.span, err = ~"can only implement trait types",
|
let sp = t.path.span, err = ~"can only implement trait types",
|
||||||
@@ -596,7 +606,7 @@ fn ty_of_item(ccx: @crate_ctxt, it: @ast::item)
|
|||||||
some(tpt) => return tpt,
|
some(tpt) => return tpt,
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
let rp = tcx.region_paramd_items.contains_key(it.id);
|
let rp = tcx.region_paramd_items.find(it.id);
|
||||||
match it.node {
|
match it.node {
|
||||||
ast::item_const(t, _) => {
|
ast::item_const(t, _) => {
|
||||||
let typ = ccx.to_ty(empty_rscope, t);
|
let typ = ccx.to_ty(empty_rscope, t);
|
||||||
@@ -609,7 +619,7 @@ fn ty_of_item(ccx: @crate_ctxt, it: @ast::item)
|
|||||||
let tofd = ty_of_fn_decl(ccx, empty_rscope, ast::proto_bare, @~[],
|
let tofd = ty_of_fn_decl(ccx, empty_rscope, ast::proto_bare, @~[],
|
||||||
decl, none, it.span);
|
decl, none, it.span);
|
||||||
let tpt = {bounds: bounds,
|
let tpt = {bounds: bounds,
|
||||||
rp: false, // functions do not have a self
|
region_param: none,
|
||||||
ty: ty::mk_fn(ccx.tcx, tofd)};
|
ty: ty::mk_fn(ccx.tcx, tofd)};
|
||||||
debug!{"type of %s (id %d) is %s",
|
debug!{"type of %s (id %d) is %s",
|
||||||
tcx.sess.str_of(it.ident), it.id, ty_to_str(tcx, tpt.ty)};
|
tcx.sess.str_of(it.ident), it.id, ty_to_str(tcx, tpt.ty)};
|
||||||
@@ -622,7 +632,7 @@ fn ty_of_item(ccx: @crate_ctxt, it: @ast::item)
|
|||||||
none => { }
|
none => { }
|
||||||
}
|
}
|
||||||
|
|
||||||
let rp = tcx.region_paramd_items.contains_key(it.id);
|
let rp = tcx.region_paramd_items.find(it.id);
|
||||||
let tpt = {
|
let tpt = {
|
||||||
let ty = {
|
let ty = {
|
||||||
let t0 = ccx.to_ty(type_rscope(rp), t);
|
let t0 = ccx.to_ty(type_rscope(rp), t);
|
||||||
@@ -634,7 +644,9 @@ fn ty_of_item(ccx: @crate_ctxt, it: @ast::item)
|
|||||||
ty::mk_with_id(tcx, t0, def_id)
|
ty::mk_with_id(tcx, t0, def_id)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
{bounds: ty_param_bounds(ccx, tps), rp: rp, ty: ty}
|
{bounds: ty_param_bounds(ccx, tps),
|
||||||
|
region_param: rp,
|
||||||
|
ty: ty}
|
||||||
};
|
};
|
||||||
|
|
||||||
tcx.tcache.insert(local_def(it.id), tpt);
|
tcx.tcache.insert(local_def(it.id), tpt);
|
||||||
@@ -644,21 +656,27 @@ fn ty_of_item(ccx: @crate_ctxt, it: @ast::item)
|
|||||||
// Create a new generic polytype.
|
// Create a new generic polytype.
|
||||||
let {bounds, substs} = mk_substs(ccx, tps, rp);
|
let {bounds, substs} = mk_substs(ccx, tps, rp);
|
||||||
let t = ty::mk_enum(tcx, local_def(it.id), substs);
|
let t = ty::mk_enum(tcx, local_def(it.id), substs);
|
||||||
let tpt = {bounds: bounds, rp: rp, ty: t};
|
let tpt = {bounds: bounds,
|
||||||
|
region_param: rp,
|
||||||
|
ty: t};
|
||||||
tcx.tcache.insert(local_def(it.id), tpt);
|
tcx.tcache.insert(local_def(it.id), tpt);
|
||||||
return tpt;
|
return tpt;
|
||||||
}
|
}
|
||||||
ast::item_trait(tps, _, ms) => {
|
ast::item_trait(tps, _, ms) => {
|
||||||
let {bounds, substs} = mk_substs(ccx, tps, rp);
|
let {bounds, substs} = mk_substs(ccx, tps, rp);
|
||||||
let t = ty::mk_trait(tcx, local_def(it.id), substs, ty::vstore_box);
|
let t = ty::mk_trait(tcx, local_def(it.id), substs, ty::vstore_box);
|
||||||
let tpt = {bounds: bounds, rp: rp, ty: t};
|
let tpt = {bounds: bounds,
|
||||||
|
region_param: rp,
|
||||||
|
ty: t};
|
||||||
tcx.tcache.insert(local_def(it.id), tpt);
|
tcx.tcache.insert(local_def(it.id), tpt);
|
||||||
return tpt;
|
return tpt;
|
||||||
}
|
}
|
||||||
ast::item_class(_, tps) => {
|
ast::item_class(_, tps) => {
|
||||||
let {bounds,substs} = mk_substs(ccx, tps, rp);
|
let {bounds,substs} = mk_substs(ccx, tps, rp);
|
||||||
let t = ty::mk_class(tcx, local_def(it.id), substs);
|
let t = ty::mk_class(tcx, local_def(it.id), substs);
|
||||||
let tpt = {bounds: bounds, rp: rp, ty: t};
|
let tpt = {bounds: bounds,
|
||||||
|
region_param: rp,
|
||||||
|
ty: t};
|
||||||
tcx.tcache.insert(local_def(it.id), tpt);
|
tcx.tcache.insert(local_def(it.id), tpt);
|
||||||
return tpt;
|
return tpt;
|
||||||
}
|
}
|
||||||
@@ -736,7 +754,7 @@ fn ty_of_foreign_fn_decl(ccx: @crate_ctxt,
|
|||||||
inputs: input_tys,
|
inputs: input_tys,
|
||||||
output: output_ty,
|
output: output_ty,
|
||||||
ret_style: ast::return_val});
|
ret_style: ast::return_val});
|
||||||
let tpt = {bounds: bounds, rp: false, ty: t_fn};
|
let tpt = {bounds: bounds, region_param: none, ty: t_fn};
|
||||||
ccx.tcx.tcache.insert(def_id, tpt);
|
ccx.tcx.tcache.insert(def_id, tpt);
|
||||||
return tpt;
|
return tpt;
|
||||||
}
|
}
|
||||||
@@ -754,10 +772,11 @@ fn mk_ty_params(ccx: @crate_ctxt, atps: ~[ast::ty_param])
|
|||||||
})}
|
})}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn mk_substs(ccx: @crate_ctxt, atps: ~[ast::ty_param], rp: bool)
|
fn mk_substs(ccx: @crate_ctxt, atps: ~[ast::ty_param],
|
||||||
|
rp: option<ty::region_variance>)
|
||||||
-> {bounds: @~[ty::param_bounds], substs: ty::substs} {
|
-> {bounds: @~[ty::param_bounds], substs: ty::substs} {
|
||||||
|
|
||||||
let {bounds, params} = mk_ty_params(ccx, atps);
|
let {bounds, params} = mk_ty_params(ccx, atps);
|
||||||
let self_r = if rp {some(ty::re_bound(ty::br_self))} else {none};
|
let self_r = rscope::bound_self_region(rp);
|
||||||
{bounds: bounds, substs: {self_r: self_r, self_ty: none, tps: params}}
|
{bounds: bounds, substs: {self_r: self_r, self_ty: none, tps: params}}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -58,7 +58,8 @@ trait combine {
|
|||||||
fn tys(a: ty::t, b: ty::t) -> cres<ty::t>;
|
fn tys(a: ty::t, b: ty::t) -> cres<ty::t>;
|
||||||
fn tps(as: &[ty::t], bs: &[ty::t]) -> cres<~[ty::t]>;
|
fn tps(as: &[ty::t], bs: &[ty::t]) -> cres<~[ty::t]>;
|
||||||
fn self_tys(a: option<ty::t>, b: option<ty::t>) -> cres<option<ty::t>>;
|
fn self_tys(a: option<ty::t>, b: option<ty::t>) -> cres<option<ty::t>>;
|
||||||
fn substs(as: &ty::substs, bs: &ty::substs) -> cres<ty::substs>;
|
fn substs(did: ast::def_id, as: &ty::substs,
|
||||||
|
bs: &ty::substs) -> cres<ty::substs>;
|
||||||
fn fns(a: &ty::fn_ty, b: &ty::fn_ty) -> cres<ty::fn_ty>;
|
fn fns(a: &ty::fn_ty, b: &ty::fn_ty) -> cres<ty::fn_ty>;
|
||||||
fn flds(a: ty::field, b: ty::field) -> cres<ty::field>;
|
fn flds(a: ty::field, b: ty::field) -> cres<ty::field>;
|
||||||
fn modes(a: ast::mode, b: ast::mode) -> cres<ast::mode>;
|
fn modes(a: ast::mode, b: ast::mode) -> cres<ast::mode>;
|
||||||
@@ -148,12 +149,57 @@ fn eq_opt_regions<C:combine>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn super_substs<C:combine>(
|
fn super_substs<C:combine>(
|
||||||
self: &C, a: &ty::substs, b: &ty::substs) -> cres<ty::substs> {
|
self: &C, did: ast::def_id,
|
||||||
|
a: &ty::substs, b: &ty::substs) -> cres<ty::substs> {
|
||||||
|
|
||||||
|
fn relate_region_param<C:combine>(
|
||||||
|
self: &C,
|
||||||
|
did: ast::def_id,
|
||||||
|
a: option<ty::region>,
|
||||||
|
b: option<ty::region>)
|
||||||
|
-> cres<option<ty::region>>
|
||||||
|
{
|
||||||
|
let polyty = ty::lookup_item_type(self.infcx().tcx, did);
|
||||||
|
match (polyty.region_param, a, b) {
|
||||||
|
(none, none, none) => {
|
||||||
|
ok(none)
|
||||||
|
}
|
||||||
|
(some(ty::rv_invariant), some(a), some(b)) => {
|
||||||
|
do eq_regions(self, a, b).then {
|
||||||
|
ok(some(a))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
(some(ty::rv_covariant), some(a), some(b)) => {
|
||||||
|
do self.regions(a, b).chain |r| {
|
||||||
|
ok(some(r))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
(some(ty::rv_contravariant), some(a), some(b)) => {
|
||||||
|
do self.contraregions(a, b).chain |r| {
|
||||||
|
ok(some(r))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
(_, _, _) => {
|
||||||
|
// If these two substitutions are for the same type (and
|
||||||
|
// they should be), then the type should either
|
||||||
|
// consistently have a region parameter or not have a
|
||||||
|
// region parameter, and that should match with the
|
||||||
|
// polytype.
|
||||||
|
self.infcx().tcx.sess.bug(
|
||||||
|
fmt!("substitution a had opt_region %s and \
|
||||||
|
b had opt_region %s with variance %?",
|
||||||
|
a.to_str(self.infcx()),
|
||||||
|
b.to_str(self.infcx()),
|
||||||
|
polyty.region_param));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
do self.tps(a.tps, b.tps).chain |tps| {
|
do self.tps(a.tps, b.tps).chain |tps| {
|
||||||
do self.self_tys(a.self_ty, b.self_ty).chain |self_ty| {
|
do self.self_tys(a.self_ty, b.self_ty).chain |self_ty| {
|
||||||
do eq_opt_regions(self, a.self_r, b.self_r).chain
|
do relate_region_param(self, did,
|
||||||
|self_r| {
|
a.self_r, b.self_r).chain |self_r|
|
||||||
|
{
|
||||||
ok({self_r: self_r, self_ty: self_ty, tps: tps})
|
ok({self_r: self_r, self_ty: self_ty, tps: tps})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -348,7 +394,7 @@ fn super_tys<C:combine>(
|
|||||||
(ty::ty_enum(a_id, ref a_substs),
|
(ty::ty_enum(a_id, ref a_substs),
|
||||||
ty::ty_enum(b_id, ref b_substs))
|
ty::ty_enum(b_id, ref b_substs))
|
||||||
if a_id == b_id => {
|
if a_id == b_id => {
|
||||||
do self.substs(a_substs, b_substs).chain |substs| {
|
do self.substs(a_id, a_substs, b_substs).chain |substs| {
|
||||||
ok(ty::mk_enum(tcx, a_id, substs))
|
ok(ty::mk_enum(tcx, a_id, substs))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -356,7 +402,7 @@ fn super_tys<C:combine>(
|
|||||||
(ty::ty_trait(a_id, ref a_substs, a_vstore),
|
(ty::ty_trait(a_id, ref a_substs, a_vstore),
|
||||||
ty::ty_trait(b_id, ref b_substs, b_vstore))
|
ty::ty_trait(b_id, ref b_substs, b_vstore))
|
||||||
if a_id == b_id => {
|
if a_id == b_id => {
|
||||||
do self.substs(a_substs, b_substs).chain |substs| {
|
do self.substs(a_id, a_substs, b_substs).chain |substs| {
|
||||||
do self.vstores(ty::terr_trait, a_vstore, b_vstore).chain |vs| {
|
do self.vstores(ty::terr_trait, a_vstore, b_vstore).chain |vs| {
|
||||||
ok(ty::mk_trait(tcx, a_id, substs, vs))
|
ok(ty::mk_trait(tcx, a_id, substs, vs))
|
||||||
}
|
}
|
||||||
@@ -365,7 +411,7 @@ fn super_tys<C:combine>(
|
|||||||
|
|
||||||
(ty::ty_class(a_id, ref a_substs), ty::ty_class(b_id, ref b_substs))
|
(ty::ty_class(a_id, ref a_substs), ty::ty_class(b_id, ref b_substs))
|
||||||
if a_id == b_id => {
|
if a_id == b_id => {
|
||||||
do self.substs(a_substs, b_substs).chain |substs| {
|
do self.substs(a_id, a_substs, b_substs).chain |substs| {
|
||||||
ok(ty::mk_class(tcx, a_id, substs))
|
ok(ty::mk_class(tcx, a_id, substs))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -151,8 +151,10 @@ impl Glb: combine {
|
|||||||
super_fns(&self, a, b)
|
super_fns(&self, a, b)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn substs(as: &ty::substs, bs: &ty::substs) -> cres<ty::substs> {
|
fn substs(did: ast::def_id,
|
||||||
super_substs(&self, as, bs)
|
as: &ty::substs,
|
||||||
|
bs: &ty::substs) -> cres<ty::substs> {
|
||||||
|
super_substs(&self, did, as, bs)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn tps(as: &[ty::t], bs: &[ty::t]) -> cres<~[ty::t]> {
|
fn tps(as: &[ty::t], bs: &[ty::t]) -> cres<~[ty::t]> {
|
||||||
|
|||||||
@@ -130,8 +130,10 @@ impl Lub: combine {
|
|||||||
super_fns(&self, a, b)
|
super_fns(&self, a, b)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn substs(as: &ty::substs, bs: &ty::substs) -> cres<ty::substs> {
|
fn substs(did: ast::def_id,
|
||||||
super_substs(&self, as, bs)
|
as: &ty::substs,
|
||||||
|
bs: &ty::substs) -> cres<ty::substs> {
|
||||||
|
super_substs(&self, did, as, bs)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn tps(as: &[ty::t], bs: &[ty::t]) -> cres<~[ty::t]> {
|
fn tps(as: &[ty::t], bs: &[ty::t]) -> cres<~[ty::t]> {
|
||||||
|
|||||||
@@ -184,8 +184,10 @@ impl Sub: combine {
|
|||||||
super_args(&self, a, b)
|
super_args(&self, a, b)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn substs(as: &ty::substs, bs: &ty::substs) -> cres<ty::substs> {
|
fn substs(did: ast::def_id,
|
||||||
super_substs(&self, as, bs)
|
as: &ty::substs,
|
||||||
|
bs: &ty::substs) -> cres<ty::substs> {
|
||||||
|
super_substs(&self, did, as, bs)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn tps(as: &[ty::t], bs: &[ty::t]) -> cres<~[ty::t]> {
|
fn tps(as: &[ty::t], bs: &[ty::t]) -> cres<~[ty::t]> {
|
||||||
|
|||||||
@@ -17,14 +17,13 @@ impl empty_rscope: region_scope {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
enum type_rscope = bool;
|
enum type_rscope = option<ty::region_variance>;
|
||||||
impl type_rscope: region_scope {
|
impl type_rscope: region_scope {
|
||||||
fn anon_region(_span: span) -> result<ty::region, ~str> {
|
fn anon_region(_span: span) -> result<ty::region, ~str> {
|
||||||
if *self {
|
match *self {
|
||||||
result::ok(ty::re_bound(ty::br_self))
|
some(_) => result::ok(ty::re_bound(ty::br_self)),
|
||||||
} else {
|
none => result::err(~"to use region types here, the containing \
|
||||||
result::err(~"to use region types here, the containing type \
|
type must be declared with a region bound")
|
||||||
must be declared with a region bound")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn named_region(span: span, id: ast::ident) -> result<ty::region, ~str> {
|
fn named_region(span: span, id: ast::ident) -> result<ty::region, ~str> {
|
||||||
@@ -39,6 +38,13 @@ impl type_rscope: region_scope {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn bound_self_region(rp: option<ty::region_variance>) -> option<ty::region> {
|
||||||
|
match rp {
|
||||||
|
some(_) => some(ty::re_bound(ty::br_self)),
|
||||||
|
none => none
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
enum anon_rscope = {anon: ty::region, base: region_scope};
|
enum anon_rscope = {anon: ty::region, base: region_scope};
|
||||||
fn in_anon_rscope<RS: region_scope copy owned>(self: RS, r: ty::region)
|
fn in_anon_rscope<RS: region_scope copy owned>(self: RS, r: ty::region)
|
||||||
-> @anon_rscope {
|
-> @anon_rscope {
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ enum ast {
|
|||||||
|
|
||||||
fn mk_add_bad1(x: &a/ast, y: &b/ast) -> ast/&a {
|
fn mk_add_bad1(x: &a/ast, y: &b/ast) -> ast/&a {
|
||||||
add(x, y) //~ ERROR cannot infer an appropriate lifetime
|
add(x, y) //~ ERROR cannot infer an appropriate lifetime
|
||||||
//~^ ERROR cannot infer an appropriate lifetime
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ enum ast {
|
|||||||
fn mk_add_bad2(x: &a/ast, y: &a/ast, z: &ast) -> ast {
|
fn mk_add_bad2(x: &a/ast, y: &a/ast, z: &ast) -> ast {
|
||||||
add(x, y)
|
add(x, y)
|
||||||
//~^ ERROR cannot infer an appropriate lifetime
|
//~^ ERROR cannot infer an appropriate lifetime
|
||||||
//~^^ ERROR cannot infer an appropriate lifetime
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
|||||||
@@ -0,0 +1,18 @@
|
|||||||
|
struct contravariant {
|
||||||
|
f: ∫
|
||||||
|
}
|
||||||
|
|
||||||
|
fn to_same_lifetime(bi: contravariant/&r) {
|
||||||
|
let bj: contravariant/&r = bi;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn to_shorter_lifetime(bi: contravariant/&r) {
|
||||||
|
let bj: contravariant/&blk = bi;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn to_longer_lifetime(bi: contravariant/&r) -> contravariant/&static {
|
||||||
|
bi //~ ERROR mismatched types
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
}
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
// 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 {
|
||||||
|
f: fn@() -> &self/int;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn to_same_lifetime(bi: contravariant/&r) {
|
||||||
|
let bj: contravariant/&r = bi;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn to_shorter_lifetime(bi: contravariant/&r) {
|
||||||
|
let bj: contravariant/&blk = bi;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn to_longer_lifetime(bi: contravariant/&r) -> contravariant/&static {
|
||||||
|
bi //~ ERROR mismatched types
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
}
|
||||||
22
src/test/compile-fail/regions-infer-covariance-due-to-arg.rs
Normal file
22
src/test/compile-fail/regions-infer-covariance-due-to-arg.rs
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
// Covariant with respect to a region:
|
||||||
|
//
|
||||||
|
// You can upcast to a *larger region* but not a smaller one.
|
||||||
|
|
||||||
|
struct covariant {
|
||||||
|
f: fn@(x: &self/int) -> int;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn to_same_lifetime(bi: covariant/&r) {
|
||||||
|
let bj: covariant/&r = bi;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn to_shorter_lifetime(bi: covariant/&r) {
|
||||||
|
let bj: covariant/&blk = bi; //~ ERROR mismatched types
|
||||||
|
}
|
||||||
|
|
||||||
|
fn to_longer_lifetime(bi: covariant/&r) -> covariant/&static {
|
||||||
|
bi
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
}
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
// Invariance with respect to a region:
|
||||||
|
//
|
||||||
|
// You cannot convert between regions.
|
||||||
|
|
||||||
|
struct invariant {
|
||||||
|
f: fn(x: &self/int) -> &self/int;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn to_same_lifetime(bi: invariant/&r) {
|
||||||
|
let bj: invariant/&r = bi;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn to_shorter_lifetime(bi: invariant/&r) {
|
||||||
|
let bj: invariant/&blk = bi; //~ ERROR mismatched types
|
||||||
|
}
|
||||||
|
|
||||||
|
fn to_longer_lifetime(bi: invariant/&r) -> invariant/&static {
|
||||||
|
bi //~ ERROR mismatched types
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
struct invariant {
|
||||||
|
f: @mut ∫
|
||||||
|
}
|
||||||
|
|
||||||
|
fn to_same_lifetime(bi: invariant/&r) {
|
||||||
|
let bj: invariant/&r = bi;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn to_shorter_lifetime(bi: invariant/&r) {
|
||||||
|
let bj: invariant/&blk = bi; //~ ERROR mismatched types
|
||||||
|
}
|
||||||
|
|
||||||
|
fn to_longer_lifetime(bi: invariant/&r) -> invariant/&static {
|
||||||
|
bi //~ ERROR mismatched types
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
struct invariant {
|
||||||
|
f: @[mut &int];
|
||||||
|
}
|
||||||
|
|
||||||
|
fn to_same_lifetime(bi: invariant/&r) {
|
||||||
|
let bj: invariant/&r = bi;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn to_shorter_lifetime(bi: invariant/&r) {
|
||||||
|
let bj: invariant/&blk = bi; //~ ERROR mismatched types
|
||||||
|
}
|
||||||
|
|
||||||
|
fn to_longer_lifetime(bi: invariant/&r) -> invariant/&static {
|
||||||
|
bi //~ ERROR mismatched types
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
struct invariant {
|
||||||
|
f: fn@(x: @mut &self/int);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn to_same_lifetime(bi: invariant/&r) {
|
||||||
|
let bj: invariant/&r = bi;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn to_shorter_lifetime(bi: invariant/&r) {
|
||||||
|
let bj: invariant/&blk = bi; //~ ERROR mismatched types
|
||||||
|
}
|
||||||
|
|
||||||
|
fn to_longer_lifetime(bi: invariant/&r) -> invariant/&static {
|
||||||
|
bi //~ ERROR mismatched types
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
struct invariant {
|
||||||
|
f: fn@() -> @mut &self/int;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn to_same_lifetime(bi: invariant/&r) {
|
||||||
|
let bj: invariant/&r = bi;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn to_shorter_lifetime(bi: invariant/&r) {
|
||||||
|
let bj: invariant/&blk = bi; //~ ERROR mismatched types
|
||||||
|
}
|
||||||
|
|
||||||
|
fn to_longer_lifetime(bi: invariant/&r) -> invariant/&static {
|
||||||
|
bi //~ ERROR mismatched types
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
struct invariant {
|
||||||
|
mut f: ∫
|
||||||
|
}
|
||||||
|
|
||||||
|
fn to_same_lifetime(bi: invariant/&r) {
|
||||||
|
let bj: invariant/&r = bi;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn to_shorter_lifetime(bi: invariant/&r) {
|
||||||
|
let bj: invariant/&blk = bi; //~ ERROR mismatched types
|
||||||
|
}
|
||||||
|
|
||||||
|
fn to_longer_lifetime(bi: invariant/&r) -> invariant/&static {
|
||||||
|
bi //~ ERROR mismatched types
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
}
|
||||||
18
src/test/run-pass/regions-infer-contravariance-due-to-ret.rs
Normal file
18
src/test/run-pass/regions-infer-contravariance-due-to-ret.rs
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
struct boxed_int {
|
||||||
|
f: ∫
|
||||||
|
}
|
||||||
|
|
||||||
|
fn max(bi: &r/boxed_int, f: &r/int) -> int {
|
||||||
|
if *bi.f > *f {*bi.f} else {*f}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn with(bi: &boxed_int) -> int {
|
||||||
|
let i = 22;
|
||||||
|
max(bi, &i)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let g = 21;
|
||||||
|
let foo = boxed_int { f: &g };
|
||||||
|
assert with(&foo) == 22;
|
||||||
|
}
|
||||||
21
src/test/run-pass/regions-infer-contravariance.rs
Normal file
21
src/test/run-pass/regions-infer-contravariance.rs
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
struct boxed_int {
|
||||||
|
f: ∫
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get(bi: &r/boxed_int) -> &r/int {
|
||||||
|
bi.f
|
||||||
|
}
|
||||||
|
|
||||||
|
fn with(bi: &r/boxed_int) {
|
||||||
|
// Here, the upcast is allowed because the `boxed_int` type is
|
||||||
|
// contravariant with respect to `&r`. See also
|
||||||
|
// compile-fail/regions-infer-invariance-due-to-mutability.rs
|
||||||
|
let bi: &blk/boxed_int/&blk = bi;
|
||||||
|
assert *get(bi) == 22;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let g = 22;
|
||||||
|
let foo = boxed_int { f: &g };
|
||||||
|
with(&foo);
|
||||||
|
}
|
||||||
@@ -20,7 +20,5 @@ fn main() {
|
|||||||
let ctxt = { v: 22u };
|
let ctxt = { v: 22u };
|
||||||
let hc = { c: &ctxt };
|
let hc = { c: &ctxt };
|
||||||
|
|
||||||
// This no longer works, interestingly, due to the ownership
|
assert get_v(hc as get_ctxt) == 22u;
|
||||||
// requirement. Perhaps this ownership requirement is too strict.
|
|
||||||
// assert get_v(hc as get_ctxt) == 22u;
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user