mirror of
https://github.com/rust-lang/rust.git
synced 2024-12-05 21:24:12 +00:00
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:
parent
8185ede1fa
commit
511e7626ae
@ -770,6 +770,7 @@ enum AncestorList = option<unsafe::Exclusive<AncestorNode>>;
|
||||
fn access_group<U>(x: &TaskGroupArc, blk: fn(TaskGroupInner) -> U) -> U {
|
||||
unsafe { x.with(blk) }
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn access_ancestors<U>(x: &unsafe::Exclusive<AncestorNode>,
|
||||
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}
|
||||
}
|
||||
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)) => {
|
||||
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,
|
||||
def: ast::def_id) -> bool {
|
||||
def: ast::def_id) -> option<ty::region_variance> {
|
||||
let cdata = cstore::get_crate_data(cstore, def.crate);
|
||||
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} );
|
||||
debug!{"got field data %?", the_field};
|
||||
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,
|
||||
|
@ -237,11 +237,11 @@ fn item_ty_param_bounds(item: ebml::doc, tcx: ty::ctxt, cdata: cmd)
|
||||
@bounds
|
||||
}
|
||||
|
||||
fn item_ty_region_param(item: ebml::doc) -> bool {
|
||||
match ebml::maybe_get_doc(item, tag_region_param) {
|
||||
some(_) => true,
|
||||
none => false
|
||||
}
|
||||
fn item_ty_region_param(item: ebml::doc) -> option<ty::region_variance> {
|
||||
ebml::maybe_get_doc(item, tag_region_param).map(|doc| {
|
||||
let d = ebml::ebml_deserializer(doc);
|
||||
ty::deserialize_region_variance(d)
|
||||
})
|
||||
}
|
||||
|
||||
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)
|
||||
} else { @~[] };
|
||||
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);
|
||||
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,
|
||||
it: @ast::item) {
|
||||
let rp = ecx.tcx.region_paramd_items.contains_key(it.id);
|
||||
if rp { do ebml_w.wr_tag(tag_region_param) { } }
|
||||
let opt_rp = ecx.tcx.region_paramd_items.find(it.id);
|
||||
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) {
|
||||
|
@ -601,8 +601,10 @@ impl ebml::writer: ebml_writer_helpers {
|
||||
self.emit_bounds(ecx, bs);
|
||||
}
|
||||
}
|
||||
do self.emit_rec_field(~"rp", 1u) {
|
||||
self.emit_bool(tpbt.rp);
|
||||
do self.emit_rec_field(~"region_param", 1u) {
|
||||
ty::serialize_opt_region_variance(
|
||||
self,
|
||||
tpbt.region_param);
|
||||
}
|
||||
do self.emit_rec_field(~"ty", 2u) {
|
||||
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, || {
|
||||
@self.read_to_vec(|| self.read_bounds(xcx) )
|
||||
}),
|
||||
rp: self.read_rec_field(~"rp", 1u, || {
|
||||
self.read_bool()
|
||||
region_param: self.read_rec_field(~"region_param", 1u, || {
|
||||
ty::deserialize_opt_region_variance(self)
|
||||
}),
|
||||
ty: self.read_rec_field(~"ty", 2u, || {
|
||||
self.read_ty(xcx)
|
||||
|
@ -16,6 +16,7 @@ import syntax::ast_util::new_def_hash;
|
||||
import syntax::ast_map;
|
||||
import dvec::{DVec, dvec};
|
||||
import metadata::csearch;
|
||||
import ty::{region_variance, rv_covariant, rv_invariant, rv_contravariant};
|
||||
|
||||
import std::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
|
||||
// dependencies until a fixed point is reached.
|
||||
|
||||
type region_paramd_items = hashmap<ast::node_id, ()>;
|
||||
type dep_map = hashmap<ast::node_id, @DVec<ast::node_id>>;
|
||||
type region_paramd_items = hashmap<ast::node_id, region_variance>;
|
||||
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_ = {
|
||||
sess: session,
|
||||
@ -381,42 +383,98 @@ type determine_rp_ctxt_ = {
|
||||
|
||||
// true when we are within an item but not within a method.
|
||||
// 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 {
|
||||
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 {
|
||||
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;
|
||||
if self.region_paramd_items.insert(id, ()) {
|
||||
debug!{"add region-parameterized item: %d (%s)", id,
|
||||
ast_map::node_id_to_str(self.ast_map, id,
|
||||
self.sess.parse_sess.interner)};
|
||||
let old_variance = self.region_paramd_items.find(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,
|
||||
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);
|
||||
} else {
|
||||
debug!{"item %d already region-parameterized", id};
|
||||
}
|
||||
}
|
||||
|
||||
fn add_dep(from: ast::node_id, to: ast::node_id) {
|
||||
debug!{"add dependency from %d -> %d (%s -> %s)",
|
||||
from, to,
|
||||
/// Indicates that the region-parameterization of the current item
|
||||
/// is dependent on the region-parameterization of the item
|
||||
/// `from`. Put another way, it indicates that the current item
|
||||
/// contains a value of type `from`, so if `from` is
|
||||
/// region-parameterized, so is the current item.
|
||||
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,
|
||||
self.sess.parse_sess.interner),
|
||||
ast_map::node_id_to_str(self.ast_map, to,
|
||||
self.sess.parse_sess.interner)};
|
||||
ast_map::node_id_to_str(self.ast_map, self.item_id,
|
||||
self.sess.parse_sess.interner),
|
||||
copy self.ambient_variance];
|
||||
let vec = match self.dep_map.find(from) {
|
||||
some(vec) => {vec}
|
||||
some(vec) => vec,
|
||||
none => {
|
||||
let vec = @dvec();
|
||||
self.dep_map.insert(from, 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
|
||||
@ -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_anon_implies_rp = self.anon_implies_rp;
|
||||
self.item_id = item_id;
|
||||
@ -471,6 +531,13 @@ impl determine_rp_ctxt {
|
||||
self.item_id = old_item_id;
|
||||
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,
|
||||
@ -484,12 +551,17 @@ fn determine_rp_in_item(item: @ast::item,
|
||||
fn determine_rp_in_fn(fk: visit::fn_kind,
|
||||
decl: ast::fn_decl,
|
||||
body: ast::blk,
|
||||
sp: span,
|
||||
id: ast::node_id,
|
||||
_sp: span,
|
||||
_id: ast::node_id,
|
||||
&&cx: determine_rp_ctxt,
|
||||
visitor: visit::vt<determine_rp_ctxt>) {
|
||||
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.
|
||||
if cx.item_id == 0 { return; }
|
||||
|
||||
// if this type directly references a region, either via a
|
||||
// region pointer like &r.ty or a region-parameterized path
|
||||
// like path/r, add to the worklist/set
|
||||
// if this type directly references a region pointer like &r/ty,
|
||||
// add to the worklist/set. Note that &r/ty is contravariant with
|
||||
// respect to &r, because &r/ty can be used whereever a *smaller*
|
||||
// region is expected (and hence is a supertype of those
|
||||
// locations)
|
||||
match ty.node {
|
||||
ast::ty_rptr(r, _) |
|
||||
ast::ty_path(@{rp: some(r), _}, _) => {
|
||||
debug!{"referenced type with regions %s",
|
||||
pprust::ty_to_str(ty, cx.sess.intr())};
|
||||
ast::ty_rptr(r, _) => {
|
||||
debug!["referenced rptr type %s",
|
||||
pprust::ty_to_str(ty, cx.sess.intr())];
|
||||
|
||||
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 => {
|
||||
debug!("referenced bare fn type with regions %s",
|
||||
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) {
|
||||
ast::def_ty(did) | ast::def_class(did, _) => {
|
||||
if did.crate == ast::local_crate {
|
||||
cx.add_dep(did.node, cx.item_id);
|
||||
cx.add_dep(did.node);
|
||||
} else {
|
||||
let cstore = cx.sess.cstore;
|
||||
if csearch::get_region_param(cstore, did) {
|
||||
debug!{"reference to external, rp'd type %s",
|
||||
pprust::ty_to_str(ty, cx.sess.intr())};
|
||||
cx.add_rp(cx.item_id);
|
||||
match csearch::get_region_param(cstore, did) {
|
||||
none => {}
|
||||
some(variance) => {
|
||||
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 {
|
||||
ast::ty_fn(*) => {
|
||||
do cx.with(cx.item_id, false) {
|
||||
visit::visit_ty(ty, cx, visitor);
|
||||
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) {
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
|
||||
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,
|
||||
@ -582,32 +717,56 @@ fn determine_rp_in_crate(sess: session,
|
||||
dep_map: int_hash(),
|
||||
worklist: dvec(),
|
||||
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(@{
|
||||
visit_fn: determine_rp_in_fn,
|
||||
visit_item: determine_rp_in_item,
|
||||
visit_ty: determine_rp_in_ty,
|
||||
visit_ty_method: determine_rp_in_ty_method,
|
||||
visit_struct_field: determine_rp_in_struct_field,
|
||||
with *visit::default_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 {
|
||||
let id = cx.worklist.pop();
|
||||
debug!{"popped %d from worklist", id};
|
||||
match cx.dep_map.find(id) {
|
||||
let c_id = cx.worklist.pop();
|
||||
let c_variance = cx.region_paramd_items.get(c_id);
|
||||
debug!["popped %d from worklist", c_id];
|
||||
match cx.dep_map.find(c_id) {
|
||||
none => {}
|
||||
some(vec) => {
|
||||
for vec.each |to_id| {
|
||||
cx.add_rp(to_id);
|
||||
some(deps) => {
|
||||
for deps.each |dep| {
|
||||
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 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)) => {
|
||||
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);
|
||||
if (*impl_bnds).len() + mth.tps.len() == 0u {
|
||||
let llfn = get_item_val(ccx, mth.id);
|
||||
|
@ -17,6 +17,8 @@ import middle::lint::{get_lint_level, allow};
|
||||
import syntax::ast::*;
|
||||
import syntax::print::pprust::*;
|
||||
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 br_hashmap;
|
||||
@ -181,6 +183,10 @@ export ast_proto_to_proto;
|
||||
export is_blockish;
|
||||
export method_call_bounds;
|
||||
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
|
||||
|
||||
@ -226,6 +232,12 @@ enum ast_ty_to_ty_cache_entry {
|
||||
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
|
||||
// is because we don't need the details in trans, we only care if there is an
|
||||
// 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
|
||||
/// region `&self` or to (unsubstituted) ty_param types
|
||||
type ty_param_bounds_and_ty = {bounds: @~[param_bounds],
|
||||
rp: bool,
|
||||
region_param: option<region_variance>,
|
||||
ty: t};
|
||||
|
||||
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 {
|
||||
{bounds: @~[], rp: false, ty: t}
|
||||
{bounds: @~[], region_param: none, ty: t}
|
||||
}
|
||||
|
||||
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 {
|
||||
|
||||
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);
|
||||
|
||||
debug!{"ast_path_to_substs_and_ty: did=%? decl_rp=%b",
|
||||
did, decl_rp};
|
||||
debug!["ast_path_to_substs_and_ty: did=%? decl_rp=%?",
|
||||
did, decl_rp];
|
||||
|
||||
// If the type is parameterized by the self region, then replace self
|
||||
// region with the current anon region binding (in other words,
|
||||
// whatever & would get replaced with).
|
||||
let self_r = match (decl_rp, path.rp) {
|
||||
(false, none) => {
|
||||
(none, none) => {
|
||||
none
|
||||
}
|
||||
(false, some(_)) => {
|
||||
(none, some(_)) => {
|
||||
tcx.sess.span_err(
|
||||
path.span,
|
||||
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)});
|
||||
none
|
||||
}
|
||||
(true, none) => {
|
||||
(some(_), none) => {
|
||||
let res = rscope.anon_region(path.span);
|
||||
let r = get_region_reporting_err(self.tcx(), path.span, res);
|
||||
some(r)
|
||||
}
|
||||
(true, some(r)) => {
|
||||
(some(_), some(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 regionmanip::{replace_bound_regions_in_fn_ty};
|
||||
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 typeck::infer::{resolve_type, force_tvar};
|
||||
|
||||
@ -84,42 +85,39 @@ type self_info = {
|
||||
explicit_self: ast::self_ty
|
||||
};
|
||||
|
||||
type fn_ctxt_ =
|
||||
struct fn_ctxt {
|
||||
// var_bindings, locals and next_var_id are shared
|
||||
// with any nested functions that capture the environment
|
||||
// (and with any functions whose environment is being captured).
|
||||
{self_impl_def_id: option<ast::def_id>,
|
||||
ret_ty: ty::t,
|
||||
// Used by loop bodies that return from the outer function
|
||||
indirect_ret_ty: option<ty::t>,
|
||||
purity: ast::purity,
|
||||
infcx: infer::infer_ctxt,
|
||||
locals: hashmap<ast::node_id, tv_vid>,
|
||||
self_impl_def_id: option<ast::def_id>;
|
||||
ret_ty: ty::t;
|
||||
// Used by loop bodies that return from the outer function
|
||||
indirect_ret_ty: option<ty::t>;
|
||||
purity: ast::purity;
|
||||
infcx: infer::infer_ctxt;
|
||||
locals: hashmap<ast::node_id, tv_vid>;
|
||||
|
||||
// Sometimes we generate region pointers where the precise region
|
||||
// to use is not known. For example, an expression like `&x.f`
|
||||
// where `x` is of type `@T`: in this case, we will be rooting
|
||||
// `x` onto the stack frame, and we could choose to root it until
|
||||
// the end of (almost) any enclosing block or expression. We
|
||||
// want to pick the narrowest block that encompasses all uses.
|
||||
//
|
||||
// What we do in such cases is to generate a region variable with
|
||||
// `region_lb` as a lower bound. The regionck pass then adds
|
||||
// other constriants based on how the variable is used and region
|
||||
// inference selects the ultimate value. Finally, borrowck is
|
||||
// charged with guaranteeing that the value whose address was taken
|
||||
// can actually be made to live as long as it needs to live.
|
||||
mut region_lb: ast::node_id,
|
||||
// Sometimes we generate region pointers where the precise region
|
||||
// to use is not known. For example, an expression like `&x.f`
|
||||
// where `x` is of type `@T`: in this case, we will be rooting
|
||||
// `x` onto the stack frame, and we could choose to root it until
|
||||
// the end of (almost) any enclosing block or expression. We
|
||||
// want to pick the narrowest block that encompasses all uses.
|
||||
//
|
||||
// What we do in such cases is to generate a region variable with
|
||||
// `region_lb` as a lower bound. The regionck pass then adds
|
||||
// other constriants based on how the variable is used and region
|
||||
// inference selects the ultimate value. Finally, borrowck is
|
||||
// charged with guaranteeing that the value whose address was taken
|
||||
// can actually be made to live as long as it needs to live.
|
||||
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_type_substs: hashmap<ast::node_id, ty::substs>,
|
||||
node_types: hashmap<ast::node_id, ty::t>;
|
||||
node_type_substs: hashmap<ast::node_id, ty::substs>;
|
||||
|
||||
ccx: @crate_ctxt};
|
||||
|
||||
enum fn_ctxt {
|
||||
fn_ctxt_(fn_ctxt_)
|
||||
ccx: @crate_ctxt;
|
||||
}
|
||||
|
||||
// Used by check_const and check_enum_variants
|
||||
@ -127,17 +125,19 @@ fn blank_fn_ctxt(ccx: @crate_ctxt, rty: ty::t,
|
||||
region_bnd: ast::node_id) -> @fn_ctxt {
|
||||
// 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
|
||||
@fn_ctxt_({self_impl_def_id: none,
|
||||
ret_ty: rty,
|
||||
indirect_ret_ty: none,
|
||||
purity: ast::pure_fn,
|
||||
infcx: infer::new_infer_ctxt(ccx.tcx),
|
||||
locals: int_hash(),
|
||||
mut region_lb: region_bnd,
|
||||
in_scope_regions: @nil,
|
||||
node_types: map::int_hash(),
|
||||
node_type_substs: map::int_hash(),
|
||||
ccx: ccx})
|
||||
@fn_ctxt {
|
||||
self_impl_def_id: none,
|
||||
ret_ty: rty,
|
||||
indirect_ret_ty: none,
|
||||
purity: ast::pure_fn,
|
||||
infcx: infer::new_infer_ctxt(ccx.tcx),
|
||||
locals: int_hash(),
|
||||
mut region_lb: region_bnd,
|
||||
in_scope_regions: @nil,
|
||||
node_types: map::int_hash(),
|
||||
node_type_substs: map::int_hash(),
|
||||
ccx: ccx
|
||||
}
|
||||
}
|
||||
|
||||
// a list of mapping from in-scope-region-names ("isr") to the
|
||||
@ -245,17 +245,19 @@ fn check_fn(ccx: @crate_ctxt,
|
||||
}
|
||||
} else { none };
|
||||
|
||||
@fn_ctxt_({self_impl_def_id: self_info.map(|info| info.def_id),
|
||||
ret_ty: ret_ty,
|
||||
indirect_ret_ty: indirect_ret_ty,
|
||||
purity: purity,
|
||||
infcx: infcx,
|
||||
locals: locals,
|
||||
mut region_lb: body.node.id,
|
||||
in_scope_regions: isr,
|
||||
node_types: node_types,
|
||||
node_type_substs: node_type_substs,
|
||||
ccx: ccx})
|
||||
@fn_ctxt {
|
||||
self_impl_def_id: self_info.map(|info| info.def_id),
|
||||
ret_ty: ret_ty,
|
||||
indirect_ret_ty: indirect_ret_ty,
|
||||
purity: purity,
|
||||
infcx: infcx,
|
||||
locals: locals,
|
||||
mut region_lb: body.node.id,
|
||||
in_scope_regions: isr,
|
||||
node_types: node_types,
|
||||
node_type_substs: node_type_substs,
|
||||
ccx: ccx
|
||||
}
|
||||
};
|
||||
|
||||
// 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);
|
||||
}
|
||||
ast::item_impl(tps, _, ty, ms) => {
|
||||
let rp = ccx.tcx.region_paramd_items.contains_key(it.id);
|
||||
debug!{"item_impl %s with id %d rp %b",
|
||||
ccx.tcx.sess.str_of(it.ident), it.id, rp};
|
||||
let rp = ccx.tcx.region_paramd_items.find(it.id);
|
||||
debug!("item_impl %s with id %d rp %?",
|
||||
ccx.tcx.sess.str_of(it.ident), it.id, rp);
|
||||
let self_ty = ccx.to_ty(rscope::type_rscope(rp), ty);
|
||||
for ms.each |m| {
|
||||
check_method(ccx, m, self_ty, local_def(it.id));
|
||||
@ -701,6 +703,15 @@ impl @fn_ctxt {
|
||||
self.region_lb = old_region_lb;
|
||||
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 {
|
||||
@ -789,14 +800,14 @@ fn impl_self_ty(fcx: @fn_ctxt,
|
||||
require_rp: bool) -> ty_param_substs_and_ty {
|
||||
let tcx = fcx.ccx.tcx;
|
||||
|
||||
let {n_tps, rp, raw_ty} = if did.crate == ast::local_crate {
|
||||
let rp = fcx.tcx().region_paramd_items.contains_key(did.node);
|
||||
let {n_tps, region_param, raw_ty} = if did.crate == ast::local_crate {
|
||||
let region_param = fcx.tcx().region_paramd_items.find(did.node);
|
||||
match check tcx.items.find(did.node) {
|
||||
some(ast_map::node_item(@{node: ast::item_impl(ts, _, st, _),
|
||||
_}, _)) => {
|
||||
{n_tps: ts.len(),
|
||||
rp: rp,
|
||||
raw_ty: fcx.ccx.to_ty(rscope::type_rscope(rp), st)}
|
||||
region_param: region_param,
|
||||
raw_ty: fcx.ccx.to_ty(rscope::type_rscope(region_param), st)}
|
||||
}
|
||||
some(ast_map::node_item(@{node: ast::item_class(_, ts),
|
||||
id: class_id, _},_)) => {
|
||||
@ -805,10 +816,9 @@ fn impl_self_ty(fcx: @fn_ctxt,
|
||||
we substitute in fresh vars for them)
|
||||
*/
|
||||
{n_tps: ts.len(),
|
||||
rp: rp,
|
||||
region_param: region_param,
|
||||
raw_ty: ty::mk_class(tcx, local_def(class_id),
|
||||
{self_r: if rp {some(ty::re_bound(ty::br_self))}
|
||||
else {none},
|
||||
{self_r: rscope::bound_self_region(region_param),
|
||||
self_ty: none,
|
||||
tps: ty::ty_params_to_tys(tcx, ts)})}
|
||||
}
|
||||
@ -818,13 +828,15 @@ fn impl_self_ty(fcx: @fn_ctxt,
|
||||
} else {
|
||||
let ity = ty::lookup_item_type(tcx, did);
|
||||
{n_tps: vec::len(*ity.bounds),
|
||||
rp: ity.rp,
|
||||
region_param: ity.region_param,
|
||||
raw_ty: ity.ty}
|
||||
};
|
||||
|
||||
let rp = rp || require_rp;
|
||||
let self_r = if rp {some(fcx.infcx.next_region_var(expr.span, expr.id))}
|
||||
else {none};
|
||||
let self_r = if region_param.is_some() || require_rp {
|
||||
some(fcx.infcx.next_region_var(expr.span, expr.id))
|
||||
} else {
|
||||
none
|
||||
};
|
||||
let tps = fcx.infcx.next_ty_vars(n_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;
|
||||
if class_id.crate == ast::local_crate {
|
||||
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) {
|
||||
some(ast_map::node_item(@{
|
||||
node: ast::item_class(_, type_parameters),
|
||||
@ -1841,12 +1853,8 @@ fn check_expr_with_unifier(fcx: @fn_ctxt,
|
||||
|
||||
type_parameter_count = type_parameters.len();
|
||||
|
||||
let self_region;
|
||||
if region_parameterized {
|
||||
self_region = some(ty::re_bound(ty::br_self));
|
||||
} else {
|
||||
self_region = none;
|
||||
}
|
||||
let self_region =
|
||||
bound_self_region(region_parameterized);
|
||||
|
||||
raw_type = ty::mk_class(tcx, class_id, {
|
||||
self_r: self_region,
|
||||
@ -1862,18 +1870,14 @@ fn check_expr_with_unifier(fcx: @fn_ctxt,
|
||||
} else {
|
||||
let item_type = ty::lookup_item_type(tcx, class_id);
|
||||
type_parameter_count = (*item_type.bounds).len();
|
||||
region_parameterized = item_type.rp;
|
||||
region_parameterized = item_type.region_param;
|
||||
raw_type = item_type.ty;
|
||||
}
|
||||
|
||||
// Generate the struct type.
|
||||
let self_region;
|
||||
if region_parameterized {
|
||||
self_region = some(fcx.infcx.next_region_var(expr.span, expr.id));
|
||||
} else {
|
||||
self_region = none;
|
||||
}
|
||||
|
||||
let self_region =
|
||||
fcx.region_var_if_parameterized(region_parameterized,
|
||||
expr.span);
|
||||
let type_parameters = fcx.infcx.next_ty_vars(type_parameter_count);
|
||||
let substitutions = {
|
||||
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 {
|
||||
let fcx = match blk.node.rules {
|
||||
ast::unchecked_blk => @fn_ctxt_({purity: ast::impure_fn with **fcx0}),
|
||||
ast::unsafe_blk => @fn_ctxt_({purity: ast::unsafe_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::default_blk => fcx0
|
||||
};
|
||||
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
|
||||
return {
|
||||
bounds: @~[],
|
||||
rp: false,
|
||||
region_param: none,
|
||||
ty: ty::mk_ptr(
|
||||
fcx.ccx.tcx,
|
||||
{
|
||||
@ -2358,19 +2362,21 @@ fn instantiate_path(fcx: @fn_ctxt,
|
||||
// determine the region bound, using the value given by the user
|
||||
// (if any) and otherwise using a fresh region variable
|
||||
let self_r = match pth.rp {
|
||||
some(r) if !tpt.rp => {
|
||||
fcx.ccx.tcx.sess.span_err
|
||||
(span, ~"this item is not region-parameterized");
|
||||
none
|
||||
}
|
||||
some(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))
|
||||
match tpt.region_param {
|
||||
none => {
|
||||
fcx.ccx.tcx.sess.span_err
|
||||
(span, ~"this item is not region-parameterized");
|
||||
none
|
||||
}
|
||||
some(_) => {
|
||||
some(ast_region_to_region(fcx, fcx, span, r))
|
||||
}
|
||||
}
|
||||
}
|
||||
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 {
|
||||
// NDM--this span is bogus.
|
||||
let self_region = if !polytype.rp {
|
||||
none
|
||||
} else {
|
||||
some(self.inference_context.next_region_var_nb(dummy_sp()))
|
||||
};
|
||||
let self_region =
|
||||
polytype.region_param.map(
|
||||
|_r| self.inference_context.next_region_var_nb(dummy_sp()));
|
||||
|
||||
let bounds_count = polytype.bounds.len();
|
||||
let type_parameters =
|
||||
|
@ -112,7 +112,7 @@ fn get_enum_variant_types(ccx: @crate_ctxt,
|
||||
enum_ty: ty::t,
|
||||
variants: ~[ast::variant],
|
||||
ty_params: ~[ast::ty_param],
|
||||
rp: bool) {
|
||||
rp: option<ty::region_variance>) {
|
||||
let tcx = ccx.tcx;
|
||||
|
||||
// Create a set of parameter types shared among all the variants.
|
||||
@ -150,7 +150,7 @@ fn get_enum_variant_types(ccx: @crate_ctxt,
|
||||
none => {}
|
||||
some(result_ty) => {
|
||||
let tpt = {bounds: ty_param_bounds(ccx, ty_params),
|
||||
rp: rp,
|
||||
region_param: rp,
|
||||
ty: result_ty};
|
||||
tcx.tcache.insert(local_def(variant.node.id), tpt);
|
||||
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,
|
||||
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
|
||||
// the impl before the trait.
|
||||
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)]]
|
||||
+ *m.tps);
|
||||
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 rp = tcx.region_paramd_items.contains_key(id);
|
||||
let region_paramd = tcx.region_paramd_items.find(id);
|
||||
match tcx.items.get(id) {
|
||||
ast_map::node_item(@{node: ast::item_trait(params, _, ms), _}, _) => {
|
||||
store_methods::<ast::trait_method>(ccx, id, ms, |m| {
|
||||
let trait_bounds = ty_param_bounds(ccx, params);
|
||||
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 {
|
||||
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
|
||||
@ -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
|
||||
// relies on the same method cache for self-calls
|
||||
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 */ }
|
||||
@ -316,7 +319,7 @@ fn compare_impl_method(tcx: ty::ctxt, sp: span,
|
||||
|
||||
fn check_methods_against_trait(ccx: @crate_ctxt,
|
||||
tps: ~[ast::ty_param],
|
||||
rp: bool,
|
||||
rp: option<ty::region_variance>,
|
||||
selfty: ty::t,
|
||||
a_trait_ty: @ast::trait_ref,
|
||||
impl_ms: ~[converted_method]) {
|
||||
@ -370,21 +373,23 @@ fn check_methods_against_trait(ccx: @crate_ctxt,
|
||||
} // fn
|
||||
|
||||
fn convert_field(ccx: @crate_ctxt,
|
||||
rp: bool,
|
||||
rp: option<ty::region_variance>,
|
||||
bounds: @~[ty::param_bounds],
|
||||
v: @ast::struct_field) {
|
||||
let tt = ccx.to_ty(type_rscope(rp), v.node.ty);
|
||||
write_ty_to_tcx(ccx.tcx, v.node.id, tt);
|
||||
/* add the field to the tcache */
|
||||
ccx.tcx.tcache.insert(local_def(v.node.id),
|
||||
{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};
|
||||
|
||||
fn convert_methods(ccx: @crate_ctxt,
|
||||
ms: ~[@ast::method],
|
||||
rp: bool,
|
||||
rp: option<ty::region_variance>,
|
||||
rcvr_bounds: @~[ty::param_bounds]) -> ~[converted_method] {
|
||||
|
||||
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
|
||||
// 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);
|
||||
{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) {
|
||||
let tcx = ccx.tcx;
|
||||
let rp = tcx.region_paramd_items.contains_key(it.id);
|
||||
debug!{"convert: item %s with id %d rp %b", tcx.sess.str_of(it.ident),
|
||||
it.id, rp};
|
||||
let rp = tcx.region_paramd_items.find(it.id);
|
||||
#debug["convert: item %s with id %d rp %?",
|
||||
tcx.sess.str_of(it.ident), it.id, rp];
|
||||
match it.node {
|
||||
// These don't define types.
|
||||
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);
|
||||
tcx.tcache.insert(local_def(it.id),
|
||||
{bounds: i_bounds,
|
||||
rp: rp,
|
||||
region_param: rp,
|
||||
ty: selfty});
|
||||
|
||||
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,
|
||||
tps: ~[ast::ty_param], tpt: ty::ty_param_bounds_and_ty,
|
||||
fn convert_struct(ccx: @crate_ctxt,
|
||||
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) {
|
||||
let tcx = ccx.tcx;
|
||||
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) );
|
||||
let t_res = ty::mk_class(
|
||||
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,
|
||||
tps: ty::ty_params_to_tys(tcx, tps)});
|
||||
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);
|
||||
tcx.tcache.insert(local_def(ctor.node.id),
|
||||
{bounds: tpt.bounds,
|
||||
rp: rp,
|
||||
region_param: rp,
|
||||
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);
|
||||
tcx.tcache.insert(local_def(dtor.node.id),
|
||||
{bounds: tpt.bounds,
|
||||
rp: rp,
|
||||
region_param: rp,
|
||||
ty: t_dtor});
|
||||
};
|
||||
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,
|
||||
m: @ast::method,
|
||||
rp: bool) -> ty::method {
|
||||
// XXX: Are the bounds correct here?
|
||||
rp: option<ty::region_variance>) -> ty::method {
|
||||
{ident: m.ident,
|
||||
tps: ty_param_bounds(ccx, m.tps),
|
||||
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,
|
||||
m: ast::ty_method,
|
||||
rp: bool) -> ty::method {
|
||||
rp: option<ty::region_variance>) -> ty::method {
|
||||
{ident: m.ident,
|
||||
tps: ty_param_bounds(self, m.tps),
|
||||
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
|
||||
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) {
|
||||
|
||||
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,
|
||||
_ => {}
|
||||
}
|
||||
let rp = tcx.region_paramd_items.contains_key(it.id);
|
||||
let rp = tcx.region_paramd_items.find(it.id);
|
||||
match it.node {
|
||||
ast::item_const(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, @~[],
|
||||
decl, none, it.span);
|
||||
let tpt = {bounds: bounds,
|
||||
rp: false, // functions do not have a self
|
||||
region_param: none,
|
||||
ty: ty::mk_fn(ccx.tcx, tofd)};
|
||||
debug!{"type of %s (id %d) is %s",
|
||||
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 => { }
|
||||
}
|
||||
|
||||
let rp = tcx.region_paramd_items.contains_key(it.id);
|
||||
let rp = tcx.region_paramd_items.find(it.id);
|
||||
let tpt = {
|
||||
let ty = {
|
||||
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)
|
||||
}
|
||||
};
|
||||
{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);
|
||||
@ -644,21 +656,27 @@ fn ty_of_item(ccx: @crate_ctxt, it: @ast::item)
|
||||
// Create a new generic polytype.
|
||||
let {bounds, substs} = mk_substs(ccx, tps, rp);
|
||||
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);
|
||||
return tpt;
|
||||
}
|
||||
ast::item_trait(tps, _, ms) => {
|
||||
let {bounds, substs} = mk_substs(ccx, tps, rp);
|
||||
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);
|
||||
return tpt;
|
||||
}
|
||||
ast::item_class(_, tps) => {
|
||||
let {bounds,substs} = mk_substs(ccx, tps, rp);
|
||||
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);
|
||||
return tpt;
|
||||
}
|
||||
@ -736,7 +754,7 @@ fn ty_of_foreign_fn_decl(ccx: @crate_ctxt,
|
||||
inputs: input_tys,
|
||||
output: output_ty,
|
||||
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);
|
||||
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} {
|
||||
|
||||
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}}
|
||||
}
|
||||
|
@ -58,7 +58,8 @@ trait combine {
|
||||
fn tys(a: ty::t, b: 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 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 flds(a: ty::field, b: ty::field) -> cres<ty::field>;
|
||||
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>(
|
||||
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.self_tys(a.self_ty, b.self_ty).chain |self_ty| {
|
||||
do eq_opt_regions(self, a.self_r, b.self_r).chain
|
||||
|self_r| {
|
||||
do relate_region_param(self, did,
|
||||
a.self_r, b.self_r).chain |self_r|
|
||||
{
|
||||
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(b_id, ref b_substs))
|
||||
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))
|
||||
}
|
||||
}
|
||||
@ -356,7 +402,7 @@ fn super_tys<C:combine>(
|
||||
(ty::ty_trait(a_id, ref a_substs, a_vstore),
|
||||
ty::ty_trait(b_id, ref b_substs, b_vstore))
|
||||
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| {
|
||||
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))
|
||||
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))
|
||||
}
|
||||
}
|
||||
|
@ -151,8 +151,10 @@ impl Glb: combine {
|
||||
super_fns(&self, a, b)
|
||||
}
|
||||
|
||||
fn substs(as: &ty::substs, bs: &ty::substs) -> cres<ty::substs> {
|
||||
super_substs(&self, as, bs)
|
||||
fn substs(did: ast::def_id,
|
||||
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]> {
|
||||
|
@ -130,8 +130,10 @@ impl Lub: combine {
|
||||
super_fns(&self, a, b)
|
||||
}
|
||||
|
||||
fn substs(as: &ty::substs, bs: &ty::substs) -> cres<ty::substs> {
|
||||
super_substs(&self, as, bs)
|
||||
fn substs(did: ast::def_id,
|
||||
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]> {
|
||||
|
@ -184,8 +184,10 @@ impl Sub: combine {
|
||||
super_args(&self, a, b)
|
||||
}
|
||||
|
||||
fn substs(as: &ty::substs, bs: &ty::substs) -> cres<ty::substs> {
|
||||
super_substs(&self, as, bs)
|
||||
fn substs(did: ast::def_id,
|
||||
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]> {
|
||||
|
@ -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 {
|
||||
fn anon_region(_span: span) -> result<ty::region, ~str> {
|
||||
if *self {
|
||||
result::ok(ty::re_bound(ty::br_self))
|
||||
} else {
|
||||
result::err(~"to use region types here, the containing type \
|
||||
must be declared with a region bound")
|
||||
match *self {
|
||||
some(_) => result::ok(ty::re_bound(ty::br_self)),
|
||||
none => result::err(~"to use region types here, the containing \
|
||||
type must be declared with a region bound")
|
||||
}
|
||||
}
|
||||
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};
|
||||
fn in_anon_rscope<RS: region_scope copy owned>(self: RS, r: ty::region)
|
||||
-> @anon_rscope {
|
||||
|
@ -5,7 +5,6 @@ enum ast {
|
||||
|
||||
fn mk_add_bad1(x: &a/ast, y: &b/ast) -> ast/&a {
|
||||
add(x, y) //~ ERROR cannot infer an appropriate lifetime
|
||||
//~^ ERROR cannot infer an appropriate lifetime
|
||||
}
|
||||
|
||||
fn main() {
|
||||
|
@ -6,7 +6,6 @@ enum ast {
|
||||
fn mk_add_bad2(x: &a/ast, y: &a/ast, z: &ast) -> ast {
|
||||
add(x, y)
|
||||
//~^ ERROR cannot infer an appropriate lifetime
|
||||
//~^^ ERROR cannot infer an appropriate lifetime
|
||||
}
|
||||
|
||||
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 hc = { c: &ctxt };
|
||||
|
||||
// This no longer works, interestingly, due to the ownership
|
||||
// requirement. Perhaps this ownership requirement is too strict.
|
||||
// assert get_v(hc as get_ctxt) == 22u;
|
||||
assert get_v(hc as get_ctxt) == 22u;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user