prevent regions from escaping in ifaces; remove &r.T syntax
This commit is contained in:
parent
eb0a34c398
commit
e0ea67a2a6
36 changed files with 411 additions and 130 deletions
|
@ -832,10 +832,10 @@ fn spawn_raw(opts: task_opts, +f: fn~()) {
|
||||||
* types; arbitrary type coercion is possible this way. The interface is safe
|
* types; arbitrary type coercion is possible this way. The interface is safe
|
||||||
* as long as all key functions are monomorphic.
|
* as long as all key functions are monomorphic.
|
||||||
*/
|
*/
|
||||||
type local_data_key<T> = fn@(+@T);
|
type local_data_key<T: owned> = fn@(+@T);
|
||||||
|
|
||||||
iface local_data { }
|
iface local_data { }
|
||||||
impl<T> of local_data for @T { }
|
impl<T: owned> of local_data for @T { }
|
||||||
|
|
||||||
// We use dvec because it's the best data structure in core. If TLS is used
|
// We use dvec because it's the best data structure in core. If TLS is used
|
||||||
// heavily in future, this could be made more efficient with a proper map.
|
// heavily in future, this could be made more efficient with a proper map.
|
||||||
|
@ -852,6 +852,7 @@ extern fn cleanup_task_local_map(map_ptr: *libc::c_void) unsafe {
|
||||||
|
|
||||||
// Gets the map from the runtime. Lazily initialises if not done so already.
|
// Gets the map from the runtime. Lazily initialises if not done so already.
|
||||||
unsafe fn get_task_local_map(task: *rust_task) -> task_local_map {
|
unsafe fn get_task_local_map(task: *rust_task) -> task_local_map {
|
||||||
|
|
||||||
// Relies on the runtime initialising the pointer to null.
|
// Relies on the runtime initialising the pointer to null.
|
||||||
// NOTE: The map's box lives in TLS invisibly referenced once. Each time
|
// NOTE: The map's box lives in TLS invisibly referenced once. Each time
|
||||||
// we retrieve it for get/set, we make another reference, which get/set
|
// we retrieve it for get/set, we make another reference, which get/set
|
||||||
|
@ -872,7 +873,9 @@ unsafe fn get_task_local_map(task: *rust_task) -> task_local_map {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn key_to_key_value<T>(key: local_data_key<T>) -> *libc::c_void {
|
unsafe fn key_to_key_value<T: owned>(
|
||||||
|
key: local_data_key<T>) -> *libc::c_void {
|
||||||
|
|
||||||
// Keys are closures, which are (fnptr,envptr) pairs. Use fnptr.
|
// Keys are closures, which are (fnptr,envptr) pairs. Use fnptr.
|
||||||
// Use reintepret_cast -- transmute would leak (forget) the closure.
|
// Use reintepret_cast -- transmute would leak (forget) the closure.
|
||||||
let pair: (*libc::c_void, *libc::c_void) = unsafe::reinterpret_cast(key);
|
let pair: (*libc::c_void, *libc::c_void) = unsafe::reinterpret_cast(key);
|
||||||
|
@ -880,8 +883,10 @@ unsafe fn key_to_key_value<T>(key: local_data_key<T>) -> *libc::c_void {
|
||||||
}
|
}
|
||||||
|
|
||||||
// If returning some(..), returns with @T with the map's reference. Careful!
|
// If returning some(..), returns with @T with the map's reference. Careful!
|
||||||
unsafe fn local_data_lookup<T>(map: task_local_map, key: local_data_key<T>)
|
unsafe fn local_data_lookup<T: owned>(
|
||||||
|
map: task_local_map, key: local_data_key<T>)
|
||||||
-> option<(uint, *libc::c_void)> {
|
-> option<(uint, *libc::c_void)> {
|
||||||
|
|
||||||
let key_value = key_to_key_value(key);
|
let key_value = key_to_key_value(key);
|
||||||
let map_pos = (*map).position(|entry|
|
let map_pos = (*map).position(|entry|
|
||||||
alt entry { some((k,_,_)) { k == key_value } none { false } }
|
alt entry { some((k,_,_)) { k == key_value } none { false } }
|
||||||
|
@ -893,8 +898,10 @@ unsafe fn local_data_lookup<T>(map: task_local_map, key: local_data_key<T>)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn local_get_helper<T>(task: *rust_task, key: local_data_key<T>,
|
unsafe fn local_get_helper<T: owned>(
|
||||||
|
task: *rust_task, key: local_data_key<T>,
|
||||||
do_pop: bool) -> option<@T> {
|
do_pop: bool) -> option<@T> {
|
||||||
|
|
||||||
let map = get_task_local_map(task);
|
let map = get_task_local_map(task);
|
||||||
// Interpret our findings from the map
|
// Interpret our findings from the map
|
||||||
do local_data_lookup(map, key).map |result| {
|
do local_data_lookup(map, key).map |result| {
|
||||||
|
@ -912,17 +919,23 @@ unsafe fn local_get_helper<T>(task: *rust_task, key: local_data_key<T>,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn local_pop<T>(task: *rust_task,
|
unsafe fn local_pop<T: owned>(
|
||||||
|
task: *rust_task,
|
||||||
key: local_data_key<T>) -> option<@T> {
|
key: local_data_key<T>) -> option<@T> {
|
||||||
|
|
||||||
local_get_helper(task, key, true)
|
local_get_helper(task, key, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn local_get<T>(task: *rust_task,
|
unsafe fn local_get<T: owned>(
|
||||||
|
task: *rust_task,
|
||||||
key: local_data_key<T>) -> option<@T> {
|
key: local_data_key<T>) -> option<@T> {
|
||||||
|
|
||||||
local_get_helper(task, key, false)
|
local_get_helper(task, key, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn local_set<T>(task: *rust_task, key: local_data_key<T>, +data: @T) {
|
unsafe fn local_set<T: owned>(
|
||||||
|
task: *rust_task, key: local_data_key<T>, +data: @T) {
|
||||||
|
|
||||||
let map = get_task_local_map(task);
|
let map = get_task_local_map(task);
|
||||||
// Store key+data as *voids. Data is invisibly referenced once; key isn't.
|
// Store key+data as *voids. Data is invisibly referenced once; key isn't.
|
||||||
let keyval = key_to_key_value(key);
|
let keyval = key_to_key_value(key);
|
||||||
|
@ -956,8 +969,10 @@ unsafe fn local_set<T>(task: *rust_task, key: local_data_key<T>, +data: @T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn local_modify<T>(task: *rust_task, key: local_data_key<T>,
|
unsafe fn local_modify<T: owned>(
|
||||||
|
task: *rust_task, key: local_data_key<T>,
|
||||||
modify_fn: fn(option<@T>) -> option<@T>) {
|
modify_fn: fn(option<@T>) -> option<@T>) {
|
||||||
|
|
||||||
// Could be more efficient by doing the lookup work, but this is easy.
|
// Could be more efficient by doing the lookup work, but this is easy.
|
||||||
let newdata = modify_fn(local_pop(task, key));
|
let newdata = modify_fn(local_pop(task, key));
|
||||||
if newdata.is_some() {
|
if newdata.is_some() {
|
||||||
|
@ -970,29 +985,37 @@ unsafe fn local_modify<T>(task: *rust_task, key: local_data_key<T>,
|
||||||
* Remove a task-local data value from the table, returning the
|
* Remove a task-local data value from the table, returning the
|
||||||
* reference that was originally created to insert it.
|
* reference that was originally created to insert it.
|
||||||
*/
|
*/
|
||||||
unsafe fn local_data_pop<T>(key: local_data_key<T>) -> option<@T> {
|
unsafe fn local_data_pop<T: owned>(
|
||||||
|
key: local_data_key<T>) -> option<@T> {
|
||||||
|
|
||||||
local_pop(rustrt::rust_get_task(), key)
|
local_pop(rustrt::rust_get_task(), key)
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Retrieve a task-local data value. It will also be kept alive in the
|
* Retrieve a task-local data value. It will also be kept alive in the
|
||||||
* table until explicitly removed.
|
* table until explicitly removed.
|
||||||
*/
|
*/
|
||||||
unsafe fn local_data_get<T>(key: local_data_key<T>) -> option<@T> {
|
unsafe fn local_data_get<T: owned>(
|
||||||
|
key: local_data_key<T>) -> option<@T> {
|
||||||
|
|
||||||
local_get(rustrt::rust_get_task(), key)
|
local_get(rustrt::rust_get_task(), key)
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Store a value in task-local data. If this key already has a value,
|
* Store a value in task-local data. If this key already has a value,
|
||||||
* that value is overwritten (and its destructor is run).
|
* that value is overwritten (and its destructor is run).
|
||||||
*/
|
*/
|
||||||
unsafe fn local_data_set<T>(key: local_data_key<T>, +data: @T) {
|
unsafe fn local_data_set<T: owned>(
|
||||||
|
key: local_data_key<T>, +data: @T) {
|
||||||
|
|
||||||
local_set(rustrt::rust_get_task(), key, data)
|
local_set(rustrt::rust_get_task(), key, data)
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Modify a task-local data value. If the function returns 'none', the
|
* Modify a task-local data value. If the function returns 'none', the
|
||||||
* data is removed (and its reference dropped).
|
* data is removed (and its reference dropped).
|
||||||
*/
|
*/
|
||||||
unsafe fn local_data_modify<T>(key: local_data_key<T>,
|
unsafe fn local_data_modify<T: owned>(
|
||||||
|
key: local_data_key<T>,
|
||||||
modify_fn: fn(option<@T>) -> option<@T>) {
|
modify_fn: fn(option<@T>) -> option<@T>) {
|
||||||
|
|
||||||
local_modify(rustrt::rust_get_task(), key, modify_fn)
|
local_modify(rustrt::rust_get_task(), key, modify_fn)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -193,7 +193,9 @@ mod tests {
|
||||||
|
|
||||||
type eqfn<T> = fn@(T, T) -> bool;
|
type eqfn<T> = fn@(T, T) -> bool;
|
||||||
|
|
||||||
fn test_parameterized<T: copy>(e: eqfn<T>, a: T, b: T, c: T, d: T) {
|
fn test_parameterized<T: copy owned>(
|
||||||
|
e: eqfn<T>, a: T, b: T, c: T, d: T) {
|
||||||
|
|
||||||
let deq: deque::t<T> = deque::create::<T>();
|
let deq: deque::t<T> = deque::create::<T>();
|
||||||
assert (deq.size() == 0u);
|
assert (deq.size() == 0u);
|
||||||
deq.add_front(a);
|
deq.add_front(a);
|
||||||
|
|
|
@ -383,8 +383,7 @@ class parser {
|
||||||
let name =
|
let name =
|
||||||
alt copy self.token {
|
alt copy self.token {
|
||||||
token::IDENT(sid, _) => {
|
token::IDENT(sid, _) => {
|
||||||
if self.look_ahead(1u) == token::DOT || // backwards compat
|
if self.look_ahead(1u) == token::BINOP(token::SLASH) {
|
||||||
self.look_ahead(1u) == token::BINOP(token::SLASH) {
|
|
||||||
self.bump(); self.bump();
|
self.bump(); self.bump();
|
||||||
some(self.get_str(sid))
|
some(self.get_str(sid))
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -345,7 +345,7 @@ fn print_type_ex(s: ps, &&ty: @ast::ty, print_colons: bool) {
|
||||||
ast::ty_rptr(region, mt) {
|
ast::ty_rptr(region, mt) {
|
||||||
alt region.node {
|
alt region.node {
|
||||||
ast::re_anon { word(s.s, ~"&"); }
|
ast::re_anon { word(s.s, ~"&"); }
|
||||||
_ { print_region(s, region); word(s.s, ~"."); }
|
_ { print_region(s, region); word(s.s, ~"/"); }
|
||||||
}
|
}
|
||||||
print_mt(s, mt);
|
print_mt(s, mt);
|
||||||
}
|
}
|
||||||
|
|
|
@ -272,7 +272,7 @@ fn enc_sty(w: io::writer, cx: @ctxt, st: ty::sty) {
|
||||||
w.write_char('I');
|
w.write_char('I');
|
||||||
w.write_uint(id.to_uint());
|
w.write_uint(id.to_uint());
|
||||||
}
|
}
|
||||||
ty::ty_param(id, did) {
|
ty::ty_param({idx: id, def_id: did}) {
|
||||||
w.write_char('p');
|
w.write_char('p');
|
||||||
w.write_str(cx.ds(did));
|
w.write_str(cx.ds(did));
|
||||||
w.write_char('|');
|
w.write_char('|');
|
||||||
|
|
|
@ -115,7 +115,7 @@ fn with_appropriate_checker(cx: ctx, id: node_id, b: fn(check_fn)) {
|
||||||
fn check_for_box(cx: ctx, id: node_id, fv: option<@freevar_entry>,
|
fn check_for_box(cx: ctx, id: node_id, fv: option<@freevar_entry>,
|
||||||
is_move: bool, var_t: ty::t, sp: span) {
|
is_move: bool, var_t: ty::t, sp: span) {
|
||||||
// all captured data must be owned
|
// all captured data must be owned
|
||||||
if !check_owned(cx, var_t, sp) { ret; }
|
if !check_owned(cx.tcx, var_t, sp) { ret; }
|
||||||
|
|
||||||
// copied in data must be copyable, but moved in data can be anything
|
// copied in data must be copyable, but moved in data can be anything
|
||||||
let is_implicit = fv.is_some();
|
let is_implicit = fv.is_some();
|
||||||
|
@ -217,7 +217,13 @@ fn check_expr(e: @expr, cx: ctx, v: visit::vt<ctx>) {
|
||||||
alt e.node {
|
alt e.node {
|
||||||
expr_assign(_, ex) |
|
expr_assign(_, ex) |
|
||||||
expr_unary(box(_), ex) | expr_unary(uniq(_), ex) |
|
expr_unary(box(_), ex) | expr_unary(uniq(_), ex) |
|
||||||
expr_ret(some(ex)) | expr_cast(ex, _) { maybe_copy(cx, ex); }
|
expr_ret(some(ex)) {
|
||||||
|
maybe_copy(cx, ex);
|
||||||
|
}
|
||||||
|
expr_cast(source, _) {
|
||||||
|
maybe_copy(cx, source);
|
||||||
|
check_cast_for_escaping_regions(cx, source, e);
|
||||||
|
}
|
||||||
expr_copy(expr) { check_copy_ex(cx, expr, false); }
|
expr_copy(expr) { check_copy_ex(cx, expr, false); }
|
||||||
// Vector add copies, but not "implicitly"
|
// Vector add copies, but not "implicitly"
|
||||||
expr_assign_op(_, _, ex) { check_copy_ex(cx, ex, false) }
|
expr_assign_op(_, _, ex) { check_copy_ex(cx, ex, false) }
|
||||||
|
@ -440,15 +446,92 @@ fn check_send(cx: ctx, ty: ty::t, sp: span) -> bool {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_owned(cx: ctx, ty: ty::t, sp: span) -> bool {
|
// note: also used from middle::typeck::regionck!
|
||||||
if !ty::kind_is_owned(ty::type_kind(cx.tcx, ty)) {
|
fn check_owned(tcx: ty::ctxt, ty: ty::t, sp: span) -> bool {
|
||||||
cx.tcx.sess.span_err(sp, ~"not an owned value");
|
if !ty::kind_is_owned(ty::type_kind(tcx, ty)) {
|
||||||
|
alt ty::get(ty).struct {
|
||||||
|
ty::ty_param(*) {
|
||||||
|
tcx.sess.span_err(sp, ~"value may contain borrowed \
|
||||||
|
pointers; use `owned` bound");
|
||||||
|
}
|
||||||
|
_ {
|
||||||
|
tcx.sess.span_err(sp, ~"value may contain borrowed \
|
||||||
|
pointers");
|
||||||
|
}
|
||||||
|
}
|
||||||
false
|
false
|
||||||
} else {
|
} else {
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// This is rather subtle. When we are casting a value to a
|
||||||
|
/// instantiated iface like `a as iface/&r`, regionck already ensures
|
||||||
|
/// that any borrowed pointers that appear in the type of `a` are
|
||||||
|
/// bounded by `&r`. However, it is possible that there are *type
|
||||||
|
/// parameters* in the type of `a`, and those *type parameters* may
|
||||||
|
/// have borrowed pointers within them. We have to guarantee that the
|
||||||
|
/// regions which appear in those type parameters are not obscured.
|
||||||
|
///
|
||||||
|
/// Therefore, we ensure that one of three conditions holds:
|
||||||
|
///
|
||||||
|
/// (1) The iface instance cannot escape the current fn. This is
|
||||||
|
/// guaranteed if the region bound `&r` is some scope within the fn
|
||||||
|
/// itself. This case is safe because whatever borrowed pointers are
|
||||||
|
/// found within the type parameter, they must enclose the fn body
|
||||||
|
/// itself.
|
||||||
|
///
|
||||||
|
/// (2) The type parameter appears in the type of the iface. For
|
||||||
|
/// example, if the type parameter is `T` and the iface type is
|
||||||
|
/// `deque<T>`, then whatever borrowed ptrs may appear in `T` also
|
||||||
|
/// appear in `deque<T>`.
|
||||||
|
///
|
||||||
|
/// (3) The type parameter is owned (and therefore does not contain
|
||||||
|
/// borrowed ptrs).
|
||||||
|
fn check_cast_for_escaping_regions(
|
||||||
|
cx: ctx,
|
||||||
|
source: @expr,
|
||||||
|
target: @expr) {
|
||||||
|
|
||||||
|
// Determine what type we are casting to; if it is not an iface, then no
|
||||||
|
// worries.
|
||||||
|
let target_ty = ty::expr_ty(cx.tcx, target);
|
||||||
|
let target_substs = alt ty::get(target_ty).struct {
|
||||||
|
ty::ty_trait(_, substs) => {substs}
|
||||||
|
_ => { ret; /* not a cast to a trait */ }
|
||||||
|
};
|
||||||
|
|
||||||
|
// Check, based on the region associated with the iface, whether it can
|
||||||
|
// possibly escape the enclosing fn item (note that all type parameters
|
||||||
|
// must have been declared on the enclosing fn item):
|
||||||
|
alt target_substs.self_r {
|
||||||
|
some(ty::re_scope(*)) => { ret; /* case (1) */ }
|
||||||
|
none | some(ty::re_static) | some(ty::re_free(*)) => {}
|
||||||
|
some(ty::re_bound(*)) | some(ty::re_var(*)) => {
|
||||||
|
cx.tcx.sess.span_bug(
|
||||||
|
source.span,
|
||||||
|
#fmt["bad region found in kind: %?", target_substs.self_r]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Assuming the iface instance can escape, then ensure that each parameter
|
||||||
|
// either appears in the iface type or is owned:
|
||||||
|
let target_params = ty::param_tys_in_type(target_ty);
|
||||||
|
let source_ty = ty::expr_ty(cx.tcx, source);
|
||||||
|
do ty::walk_ty(source_ty) |ty| {
|
||||||
|
alt ty::get(ty).struct {
|
||||||
|
ty::ty_param(source_param) => {
|
||||||
|
if target_params.contains(source_param) {
|
||||||
|
/* case (2) */
|
||||||
|
} else {
|
||||||
|
check_owned(cx.tcx, ty, source.span); /* case (3) */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// Local Variables:
|
// Local Variables:
|
||||||
// mode: rust
|
// mode: rust
|
||||||
|
|
|
@ -1317,7 +1317,7 @@ enum copy_action { INIT, DROP_EXISTING, }
|
||||||
fn type_is_structural_or_param(t: ty::t) -> bool {
|
fn type_is_structural_or_param(t: ty::t) -> bool {
|
||||||
if ty::type_is_structural(t) { ret true; }
|
if ty::type_is_structural(t) { ret true; }
|
||||||
alt ty::get(t).struct {
|
alt ty::get(t).struct {
|
||||||
ty::ty_param(_, _) { ret true; }
|
ty::ty_param(*) { ret true; }
|
||||||
_ { ret false; }
|
_ { ret false; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -272,7 +272,7 @@ impl methods for reflector {
|
||||||
ty::ty_trait(_, _) { self.leaf(~"trait") }
|
ty::ty_trait(_, _) { self.leaf(~"trait") }
|
||||||
ty::ty_var(_) { self.leaf(~"var") }
|
ty::ty_var(_) { self.leaf(~"var") }
|
||||||
ty::ty_var_integral(_) { self.leaf(~"var_integral") }
|
ty::ty_var_integral(_) { self.leaf(~"var_integral") }
|
||||||
ty::ty_param(n, _) { self.visit(~"param", ~[self.c_uint(n)]) }
|
ty::ty_param(p) { self.visit(~"param", ~[self.c_uint(p.idx)]) }
|
||||||
ty::ty_self { self.leaf(~"self") }
|
ty::ty_self { self.leaf(~"self") }
|
||||||
ty::ty_type { self.leaf(~"type") }
|
ty::ty_type { self.leaf(~"type") }
|
||||||
ty::ty_opaque_box { self.leaf(~"opaque_box") }
|
ty::ty_opaque_box { self.leaf(~"opaque_box") }
|
||||||
|
|
|
@ -137,8 +137,8 @@ fn type_needs_inner(cx: ctx, use: uint, ty: ty::t,
|
||||||
}
|
}
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
ty::ty_param(n, _) {
|
ty::ty_param(p) {
|
||||||
cx.uses[n] |= use;
|
cx.uses[p.idx] |= use;
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
_ { true }
|
_ { true }
|
||||||
|
|
|
@ -166,6 +166,7 @@ export terr_regions_differ, terr_mutability, terr_purity_mismatch;
|
||||||
export terr_proto_mismatch;
|
export terr_proto_mismatch;
|
||||||
export terr_ret_style_mismatch;
|
export terr_ret_style_mismatch;
|
||||||
export purity_to_str;
|
export purity_to_str;
|
||||||
|
export param_tys_in_type;
|
||||||
|
|
||||||
// Data types
|
// Data types
|
||||||
|
|
||||||
|
@ -312,6 +313,8 @@ type fn_ty = {purity: ast::purity,
|
||||||
output: t,
|
output: t,
|
||||||
ret_style: ret_style};
|
ret_style: ret_style};
|
||||||
|
|
||||||
|
type param_ty = {idx: uint, def_id: def_id};
|
||||||
|
|
||||||
// See discussion at head of region.rs
|
// See discussion at head of region.rs
|
||||||
enum region {
|
enum region {
|
||||||
re_bound(bound_region),
|
re_bound(bound_region),
|
||||||
|
@ -370,7 +373,7 @@ enum sty {
|
||||||
ty_var(tv_vid), // type variable during typechecking
|
ty_var(tv_vid), // type variable during typechecking
|
||||||
ty_var_integral(tvi_vid), // type variable during typechecking, for
|
ty_var_integral(tvi_vid), // type variable during typechecking, for
|
||||||
// integral types only
|
// integral types only
|
||||||
ty_param(uint, def_id), // type parameter
|
ty_param(param_ty), // type parameter
|
||||||
ty_self, // special, implicit `self` type parameter
|
ty_self, // special, implicit `self` type parameter
|
||||||
|
|
||||||
// "Fake" types, used for trans purposes
|
// "Fake" types, used for trans purposes
|
||||||
|
@ -579,7 +582,7 @@ fn mk_t_with_id(cx: ctxt, st: sty, o_def_id: option<ast::def_id>) -> t {
|
||||||
ty_nil | ty_bot | ty_bool | ty_int(_) | ty_float(_) | ty_uint(_) |
|
ty_nil | ty_bot | ty_bool | ty_int(_) | ty_float(_) | ty_uint(_) |
|
||||||
ty_estr(_) | ty_type | ty_opaque_closure_ptr(_) |
|
ty_estr(_) | ty_type | ty_opaque_closure_ptr(_) |
|
||||||
ty_opaque_box {}
|
ty_opaque_box {}
|
||||||
ty_param(_, _) { flags |= has_params as uint; }
|
ty_param(_) { flags |= has_params as uint; }
|
||||||
ty_var(_) | ty_var_integral(_) { flags |= needs_infer as uint; }
|
ty_var(_) | ty_var_integral(_) { flags |= needs_infer as uint; }
|
||||||
ty_self { flags |= has_self as uint; }
|
ty_self { flags |= has_self as uint; }
|
||||||
ty_enum(_, substs) | ty_class(_, substs) | ty_trait(_, substs) {
|
ty_enum(_, substs) | ty_class(_, substs) | ty_trait(_, substs) {
|
||||||
|
@ -713,7 +716,9 @@ fn mk_var_integral(cx: ctxt, v: tvi_vid) -> t {
|
||||||
|
|
||||||
fn mk_self(cx: ctxt) -> t { mk_t(cx, ty_self) }
|
fn mk_self(cx: ctxt) -> t { mk_t(cx, ty_self) }
|
||||||
|
|
||||||
fn mk_param(cx: ctxt, n: uint, k: def_id) -> t { mk_t(cx, ty_param(n, k)) }
|
fn mk_param(cx: ctxt, n: uint, k: def_id) -> t {
|
||||||
|
mk_t(cx, ty_param({idx: n, def_id: k}))
|
||||||
|
}
|
||||||
|
|
||||||
fn mk_type(cx: ctxt) -> t { mk_t(cx, ty_type) }
|
fn mk_type(cx: ctxt) -> t { mk_t(cx, ty_type) }
|
||||||
|
|
||||||
|
@ -761,7 +766,7 @@ fn maybe_walk_ty(ty: t, f: fn(t) -> bool) {
|
||||||
ty_nil | ty_bot | ty_bool | ty_int(_) | ty_uint(_) | ty_float(_) |
|
ty_nil | ty_bot | ty_bool | ty_int(_) | ty_uint(_) | ty_float(_) |
|
||||||
ty_estr(_) | ty_type | ty_opaque_box | ty_self |
|
ty_estr(_) | ty_type | ty_opaque_box | ty_self |
|
||||||
ty_opaque_closure_ptr(_) | ty_var(_) | ty_var_integral(_) |
|
ty_opaque_closure_ptr(_) | ty_var(_) | ty_var_integral(_) |
|
||||||
ty_param(_, _) {
|
ty_param(_) {
|
||||||
}
|
}
|
||||||
ty_box(tm) | ty_evec(tm, _) | ty_unboxed_vec(tm) |
|
ty_box(tm) | ty_evec(tm, _) | ty_unboxed_vec(tm) |
|
||||||
ty_ptr(tm) | ty_rptr(_, tm) {
|
ty_ptr(tm) | ty_rptr(_, tm) {
|
||||||
|
@ -982,7 +987,7 @@ fn subst_tps(cx: ctxt, tps: ~[t], typ: t) -> t {
|
||||||
let tb = ty::get(typ);
|
let tb = ty::get(typ);
|
||||||
if !tbox_has_flag(tb, has_params) { ret typ; }
|
if !tbox_has_flag(tb, has_params) { ret typ; }
|
||||||
alt tb.struct {
|
alt tb.struct {
|
||||||
ty_param(idx, _) { tps[idx] }
|
ty_param(p) { tps[p.idx] }
|
||||||
sty { fold_sty_to_ty(cx, sty, |t| subst_tps(cx, tps, t)) }
|
sty { fold_sty_to_ty(cx, sty, |t| subst_tps(cx, tps, t)) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1019,7 +1024,7 @@ fn subst(cx: ctxt,
|
||||||
let tb = get(typ);
|
let tb = get(typ);
|
||||||
if !tbox_has_flag(tb, needs_subst) { ret typ; }
|
if !tbox_has_flag(tb, needs_subst) { ret typ; }
|
||||||
alt tb.struct {
|
alt tb.struct {
|
||||||
ty_param(idx, _) {substs.tps[idx]}
|
ty_param(p) {substs.tps[p.idx]}
|
||||||
ty_self {substs.self_ty.get()}
|
ty_self {substs.self_ty.get()}
|
||||||
_ {
|
_ {
|
||||||
fold_regions_and_ty(
|
fold_regions_and_ty(
|
||||||
|
@ -1608,8 +1613,8 @@ fn type_kind(cx: ctxt, ty: t) -> kind {
|
||||||
lowest
|
lowest
|
||||||
}
|
}
|
||||||
|
|
||||||
ty_param(_, did) {
|
ty_param(p) {
|
||||||
param_bounds_to_kind(cx.ty_param_bounds.get(did.node))
|
param_bounds_to_kind(cx.ty_param_bounds.get(p.def_id.node))
|
||||||
}
|
}
|
||||||
|
|
||||||
// self is a special type parameter that can only appear in ifaces; it
|
// self is a special type parameter that can only appear in ifaces; it
|
||||||
|
@ -1666,7 +1671,7 @@ fn is_instantiable(cx: ctxt, r_ty: t) -> bool {
|
||||||
ty_fn(_) |
|
ty_fn(_) |
|
||||||
ty_var(_) |
|
ty_var(_) |
|
||||||
ty_var_integral(_) |
|
ty_var_integral(_) |
|
||||||
ty_param(_, _) |
|
ty_param(_) |
|
||||||
ty_self |
|
ty_self |
|
||||||
ty_type |
|
ty_type |
|
||||||
ty_opaque_box |
|
ty_opaque_box |
|
||||||
|
@ -1855,7 +1860,7 @@ fn type_is_pod(cx: ctxt, ty: t) -> bool {
|
||||||
ty_evec(mt, vstore_fixed(_)) | ty_unboxed_vec(mt) {
|
ty_evec(mt, vstore_fixed(_)) | ty_unboxed_vec(mt) {
|
||||||
result = type_is_pod(cx, mt.ty);
|
result = type_is_pod(cx, mt.ty);
|
||||||
}
|
}
|
||||||
ty_param(_, _) { result = false; }
|
ty_param(_) { result = false; }
|
||||||
ty_opaque_closure_ptr(_) { result = true; }
|
ty_opaque_closure_ptr(_) { result = true; }
|
||||||
ty_class(did, substs) {
|
ty_class(did, substs) {
|
||||||
result = vec::any(lookup_class_fields(cx, did), |f| {
|
result = vec::any(lookup_class_fields(cx, did), |f| {
|
||||||
|
@ -1899,7 +1904,7 @@ fn type_is_c_like_enum(cx: ctxt, ty: t) -> bool {
|
||||||
|
|
||||||
fn type_param(ty: t) -> option<uint> {
|
fn type_param(ty: t) -> option<uint> {
|
||||||
alt get(ty).struct {
|
alt get(ty).struct {
|
||||||
ty_param(id, _) { ret some(id); }
|
ty_param(p) { ret some(p.idx); }
|
||||||
_ {/* fall through */ }
|
_ {/* fall through */ }
|
||||||
}
|
}
|
||||||
ret none;
|
ret none;
|
||||||
|
@ -2038,7 +2043,7 @@ fn hash_type_structure(st: sty) -> uint {
|
||||||
ty_self { 28u }
|
ty_self { 28u }
|
||||||
ty_var(v) { hash_uint(29u, v.to_uint()) }
|
ty_var(v) { hash_uint(29u, v.to_uint()) }
|
||||||
ty_var_integral(v) { hash_uint(30u, v.to_uint()) }
|
ty_var_integral(v) { hash_uint(30u, v.to_uint()) }
|
||||||
ty_param(pid, did) { hash_def(hash_uint(31u, pid), did) }
|
ty_param(p) { hash_def(hash_uint(31u, p.idx), p.def_id) }
|
||||||
ty_type { 32u }
|
ty_type { 32u }
|
||||||
ty_bot { 34u }
|
ty_bot { 34u }
|
||||||
ty_ptr(mt) { hash_subty(35u, mt.ty) }
|
ty_ptr(mt) { hash_subty(35u, mt.ty) }
|
||||||
|
@ -2219,6 +2224,22 @@ fn method_idx(id: ast::ident, meths: ~[method]) -> option<uint> {
|
||||||
ret none;
|
ret none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns a vector containing the indices of all type parameters that appear
|
||||||
|
/// in `ty`. The vector may contain duplicates. Probably should be converted
|
||||||
|
/// to a bitset or some other representation.
|
||||||
|
fn param_tys_in_type(ty: t) -> ~[param_ty] {
|
||||||
|
let mut rslt = ~[];
|
||||||
|
do walk_ty(ty) |ty| {
|
||||||
|
alt get(ty).struct {
|
||||||
|
ty_param(p) {
|
||||||
|
vec::push(rslt, p);
|
||||||
|
}
|
||||||
|
_ { }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
rslt
|
||||||
|
}
|
||||||
|
|
||||||
fn occurs_check(tcx: ctxt, sp: span, vid: tv_vid, rt: t) {
|
fn occurs_check(tcx: ctxt, sp: span, vid: tv_vid, rt: t) {
|
||||||
|
|
||||||
// Returns a vec of all the type variables occurring in `ty`. It may
|
// Returns a vec of all the type variables occurring in `ty`. It may
|
||||||
|
@ -2341,7 +2362,7 @@ fn ty_sort_str(cx: ctxt, t: t) -> ~str {
|
||||||
ty_tup(_) { ~"tuple" }
|
ty_tup(_) { ~"tuple" }
|
||||||
ty_var(_) { ~"variable" }
|
ty_var(_) { ~"variable" }
|
||||||
ty_var_integral(_) { ~"integral variable" }
|
ty_var_integral(_) { ~"integral variable" }
|
||||||
ty_param(_, _) { ~"type parameter" }
|
ty_param(_) { ~"type parameter" }
|
||||||
ty_self { ~"self" }
|
ty_self { ~"self" }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -68,7 +68,7 @@ fn get_region_reporting_err(tcx: ty::ctxt,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn ast_region_to_region<AC: ast_conv, RS: region_scope>(
|
fn ast_region_to_region<AC: ast_conv, RS: region_scope copy owned>(
|
||||||
self: AC, rscope: RS, span: span, a_r: @ast::region) -> ty::region {
|
self: AC, rscope: RS, span: span, a_r: @ast::region) -> ty::region {
|
||||||
|
|
||||||
let res = alt a_r.node {
|
let res = alt a_r.node {
|
||||||
|
@ -79,7 +79,7 @@ fn ast_region_to_region<AC: ast_conv, RS: region_scope>(
|
||||||
get_region_reporting_err(self.tcx(), span, res)
|
get_region_reporting_err(self.tcx(), span, res)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn ast_path_to_substs_and_ty<AC: ast_conv, RS: region_scope copy>(
|
fn ast_path_to_substs_and_ty<AC: ast_conv, RS: region_scope copy owned>(
|
||||||
self: AC, rscope: RS, did: ast::def_id,
|
self: AC, rscope: RS, did: ast::def_id,
|
||||||
path: @ast::path) -> ty_param_substs_and_ty {
|
path: @ast::path) -> ty_param_substs_and_ty {
|
||||||
|
|
||||||
|
@ -128,7 +128,7 @@ fn ast_path_to_substs_and_ty<AC: ast_conv, RS: region_scope copy>(
|
||||||
{substs: substs, ty: ty::subst(tcx, substs, decl_ty)}
|
{substs: substs, ty: ty::subst(tcx, substs, decl_ty)}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn ast_path_to_ty<AC: ast_conv, RS: region_scope copy>(
|
fn ast_path_to_ty<AC: ast_conv, RS: region_scope copy owned>(
|
||||||
self: AC,
|
self: AC,
|
||||||
rscope: RS,
|
rscope: RS,
|
||||||
did: ast::def_id,
|
did: ast::def_id,
|
||||||
|
@ -151,10 +151,10 @@ const NO_TPS: uint = 2u;
|
||||||
// Parses the programmer's textual representation of a type into our
|
// Parses the programmer's textual representation of a type into our
|
||||||
// internal notion of a type. `getter` is a function that returns the type
|
// internal notion of a type. `getter` is a function that returns the type
|
||||||
// corresponding to a definition ID:
|
// corresponding to a definition ID:
|
||||||
fn ast_ty_to_ty<AC: ast_conv, RS: region_scope copy>(
|
fn ast_ty_to_ty<AC: ast_conv, RS: region_scope copy owned>(
|
||||||
self: AC, rscope: RS, &&ast_ty: @ast::ty) -> ty::t {
|
self: AC, rscope: RS, &&ast_ty: @ast::ty) -> ty::t {
|
||||||
|
|
||||||
fn ast_mt_to_mt<AC: ast_conv, RS: region_scope copy>(
|
fn ast_mt_to_mt<AC: ast_conv, RS: region_scope copy owned>(
|
||||||
self: AC, rscope: RS, mt: ast::mt) -> ty::mt {
|
self: AC, rscope: RS, mt: ast::mt) -> ty::mt {
|
||||||
|
|
||||||
ret {ty: ast_ty_to_ty(self, rscope, mt.ty), mutbl: mt.mutbl};
|
ret {ty: ast_ty_to_ty(self, rscope, mt.ty), mutbl: mt.mutbl};
|
||||||
|
@ -162,7 +162,7 @@ fn ast_ty_to_ty<AC: ast_conv, RS: region_scope copy>(
|
||||||
|
|
||||||
// Handle @, ~, and & being able to mean estrs and evecs.
|
// Handle @, ~, and & being able to mean estrs and evecs.
|
||||||
// If a_seq_ty is a str or a vec, make it an estr/evec
|
// If a_seq_ty is a str or a vec, make it an estr/evec
|
||||||
fn mk_maybe_vstore<AC: ast_conv, RS: region_scope copy>(
|
fn mk_maybe_vstore<AC: ast_conv, RS: region_scope copy owned>(
|
||||||
self: AC, rscope: RS, a_seq_ty: ast::mt, vst: ty::vstore,
|
self: AC, rscope: RS, a_seq_ty: ast::mt, vst: ty::vstore,
|
||||||
constr: fn(ty::mt) -> ty::t) -> ty::t {
|
constr: fn(ty::mt) -> ty::t) -> ty::t {
|
||||||
|
|
||||||
|
@ -351,7 +351,7 @@ fn ast_ty_to_ty<AC: ast_conv, RS: region_scope copy>(
|
||||||
ret typ;
|
ret typ;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn ty_of_arg<AC: ast_conv, RS: region_scope copy>(
|
fn ty_of_arg<AC: ast_conv, RS: region_scope copy owned>(
|
||||||
self: AC, rscope: RS, a: ast::arg,
|
self: AC, rscope: RS, a: ast::arg,
|
||||||
expected_ty: option<ty::arg>) -> ty::arg {
|
expected_ty: option<ty::arg>) -> ty::arg {
|
||||||
|
|
||||||
|
@ -394,7 +394,7 @@ fn ty_of_arg<AC: ast_conv, RS: region_scope copy>(
|
||||||
type expected_tys = option<{inputs: ~[ty::arg],
|
type expected_tys = option<{inputs: ~[ty::arg],
|
||||||
output: ty::t}>;
|
output: ty::t}>;
|
||||||
|
|
||||||
fn ty_of_fn_decl<AC: ast_conv, RS: region_scope copy>(
|
fn ty_of_fn_decl<AC: ast_conv, RS: region_scope copy owned>(
|
||||||
self: AC, rscope: RS,
|
self: AC, rscope: RS,
|
||||||
proto: ast::proto,
|
proto: ast::proto,
|
||||||
decl: ast::fn_decl,
|
decl: ast::fn_decl,
|
||||||
|
|
|
@ -2154,7 +2154,7 @@ fn check_bounds_are_used(ccx: @crate_ctxt,
|
||||||
|_r| {},
|
|_r| {},
|
||||||
|t| {
|
|t| {
|
||||||
alt ty::get(t).struct {
|
alt ty::get(t).struct {
|
||||||
ty::ty_param(idx, _) { tps_used[idx] = true; }
|
ty::ty_param({idx, _}) { tps_used[idx] = true; }
|
||||||
_ { }
|
_ { }
|
||||||
}
|
}
|
||||||
true
|
true
|
||||||
|
|
|
@ -87,8 +87,8 @@ class lookup {
|
||||||
loop {
|
loop {
|
||||||
// First, see whether this is an interface-bounded parameter.
|
// First, see whether this is an interface-bounded parameter.
|
||||||
alt ty::get(self.self_ty).struct {
|
alt ty::get(self.self_ty).struct {
|
||||||
ty::ty_param(n, did) {
|
ty::ty_param(p) {
|
||||||
self.add_candidates_from_param(n, did);
|
self.add_candidates_from_param(p.idx, p.def_id);
|
||||||
}
|
}
|
||||||
ty::ty_trait(did, substs) {
|
ty::ty_trait(did, substs) {
|
||||||
self.add_candidates_from_trait(did, substs);
|
self.add_candidates_from_trait(did, substs);
|
||||||
|
|
|
@ -20,23 +20,59 @@ this point a bit better.
|
||||||
import util::ppaux;
|
import util::ppaux;
|
||||||
import syntax::print::pprust;
|
import syntax::print::pprust;
|
||||||
import infer::{resolve_type, resolve_all, force_all,
|
import infer::{resolve_type, resolve_all, force_all,
|
||||||
resolve_rvar, force_rvar};
|
resolve_rvar, force_rvar, fres};
|
||||||
|
import middle::kind::check_owned;
|
||||||
|
|
||||||
type rcx = @{fcx: @fn_ctxt, mut errors_reported: uint};
|
enum rcx { rcx_({fcx: @fn_ctxt, mut errors_reported: uint}) }
|
||||||
type rvt = visit::vt<rcx>;
|
type rvt = visit::vt<@rcx>;
|
||||||
|
|
||||||
|
impl methods for @rcx {
|
||||||
|
/// Try to resolve the type for the given node.
|
||||||
|
///
|
||||||
|
/// Note one important point: we do not attempt to resolve *region
|
||||||
|
/// variables* here. This is because regionck is essentially adding
|
||||||
|
/// constraints to those region variables and so may yet influence
|
||||||
|
/// how they are resolved.
|
||||||
|
///
|
||||||
|
/// Consider this silly example:
|
||||||
|
///
|
||||||
|
/// fn borrow(x: &int) -> &int {x}
|
||||||
|
/// fn foo(x: @int) -> int { /* block: B */
|
||||||
|
/// let b = borrow(x); /* region: <R0> */
|
||||||
|
/// *b
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// Here, the region of `b` will be `<R0>`. `<R0>` is constrainted
|
||||||
|
/// to be some subregion of the block B and some superregion of
|
||||||
|
/// the call. If we forced it now, we'd choose the smaller region
|
||||||
|
/// (the call). But that would make the *b illegal. Since we don't
|
||||||
|
/// resolve, the type of b will be `&<R0>.int` and then `*b` will require
|
||||||
|
/// that `<R0>` be bigger than the let and the `*b` expression, so we
|
||||||
|
/// will effectively resolve `<R0>` to be the block B.
|
||||||
|
fn resolve_type(unresolved_ty: ty::t) -> fres<ty::t> {
|
||||||
|
resolve_type(self.fcx.infcx, unresolved_ty,
|
||||||
|
(resolve_all | force_all) -
|
||||||
|
(resolve_rvar | force_rvar))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Try to resolve the type for the given node.
|
||||||
|
fn resolve_node_type(id: ast::node_id) -> fres<ty::t> {
|
||||||
|
self.resolve_type(self.fcx.node_ty(id))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn regionck_expr(fcx: @fn_ctxt, e: @ast::expr) {
|
fn regionck_expr(fcx: @fn_ctxt, e: @ast::expr) {
|
||||||
let rcx = @{fcx:fcx, mut errors_reported: 0u};
|
let rcx = rcx_({fcx:fcx, mut errors_reported: 0u});
|
||||||
let v = regionck_visitor();
|
let v = regionck_visitor();
|
||||||
v.visit_expr(e, rcx, v);
|
v.visit_expr(e, @rcx, v);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn regionck_fn(fcx: @fn_ctxt,
|
fn regionck_fn(fcx: @fn_ctxt,
|
||||||
_decl: ast::fn_decl,
|
_decl: ast::fn_decl,
|
||||||
blk: ast::blk) {
|
blk: ast::blk) {
|
||||||
let rcx = @{fcx:fcx, mut errors_reported: 0u};
|
let rcx = rcx_({fcx:fcx, mut errors_reported: 0u});
|
||||||
let v = regionck_visitor();
|
let v = regionck_visitor();
|
||||||
v.visit_block(blk, rcx, v);
|
v.visit_block(blk, @rcx, v);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn regionck_visitor() -> rvt {
|
fn regionck_visitor() -> rvt {
|
||||||
|
@ -49,11 +85,11 @@ fn regionck_visitor() -> rvt {
|
||||||
with *visit::default_visitor()})
|
with *visit::default_visitor()})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_item(_item: @ast::item, &&_rcx: rcx, _v: rvt) {
|
fn visit_item(_item: @ast::item, &&_rcx: @rcx, _v: rvt) {
|
||||||
// Ignore items
|
// Ignore items
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_local(l: @ast::local, &&rcx: rcx, v: rvt) {
|
fn visit_local(l: @ast::local, &&rcx: @rcx, v: rvt) {
|
||||||
let e = rcx.errors_reported;
|
let e = rcx.errors_reported;
|
||||||
v.visit_pat(l.node.pat, rcx, v);
|
v.visit_pat(l.node.pat, rcx, v);
|
||||||
if e != rcx.errors_reported {
|
if e != rcx.errors_reported {
|
||||||
|
@ -66,7 +102,7 @@ fn visit_local(l: @ast::local, &&rcx: rcx, v: rvt) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_pat(p: @ast::pat, &&rcx: rcx, v: rvt) {
|
fn visit_pat(p: @ast::pat, &&rcx: @rcx, v: rvt) {
|
||||||
let fcx = rcx.fcx;
|
let fcx = rcx.fcx;
|
||||||
alt p.node {
|
alt p.node {
|
||||||
ast::pat_ident(path, _)
|
ast::pat_ident(path, _)
|
||||||
|
@ -80,11 +116,11 @@ fn visit_pat(p: @ast::pat, &&rcx: rcx, v: rvt) {
|
||||||
visit::visit_pat(p, rcx, v);
|
visit::visit_pat(p, rcx, v);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_block(b: ast::blk, &&rcx: rcx, v: rvt) {
|
fn visit_block(b: ast::blk, &&rcx: @rcx, v: rvt) {
|
||||||
visit::visit_block(b, rcx, v);
|
visit::visit_block(b, rcx, v);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_expr(e: @ast::expr, &&rcx: rcx, v: rvt) {
|
fn visit_expr(e: @ast::expr, &&rcx: @rcx, v: rvt) {
|
||||||
#debug["visit_expr(e=%s)", pprust::expr_to_str(e)];
|
#debug["visit_expr(e=%s)", pprust::expr_to_str(e)];
|
||||||
|
|
||||||
alt e.node {
|
alt e.node {
|
||||||
|
@ -99,6 +135,41 @@ fn visit_expr(e: @ast::expr, &&rcx: rcx, v: rvt) {
|
||||||
_ { }
|
_ { }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ast::expr_cast(source, _) {
|
||||||
|
// Determine if we are casting `source` to an iface instance.
|
||||||
|
// If so, we have to be sure that the type of the source obeys
|
||||||
|
// the iface's region bound.
|
||||||
|
//
|
||||||
|
// Note: there is a subtle point here concerning type
|
||||||
|
// parameters. It is possible that the type of `source`
|
||||||
|
// contains type parameters, which in turn may contain regions
|
||||||
|
// that are not visible to us (only the caller knows about
|
||||||
|
// them). The kind checker is ultimately responsible for
|
||||||
|
// guaranteeing region safety in that particular case. There
|
||||||
|
// is an extensive comment on the function
|
||||||
|
// check_cast_for_escaping_regions() in kind.rs explaining how
|
||||||
|
// it goes about doing that.
|
||||||
|
alt rcx.resolve_node_type(e.id) {
|
||||||
|
result::err(_) => { ret; /* typeck will fail anyhow */ }
|
||||||
|
result::ok(target_ty) => {
|
||||||
|
alt ty::get(target_ty).struct {
|
||||||
|
ty::ty_trait(_, substs) {
|
||||||
|
let iface_region = alt substs.self_r {
|
||||||
|
some(r) => {r}
|
||||||
|
none => {ty::re_static}
|
||||||
|
};
|
||||||
|
let source_ty = rcx.fcx.expr_ty(source);
|
||||||
|
constrain_regions_in_type(rcx, iface_region,
|
||||||
|
e.span, source_ty);
|
||||||
|
}
|
||||||
|
_ { }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
_ { }
|
_ { }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -106,7 +177,7 @@ fn visit_expr(e: @ast::expr, &&rcx: rcx, v: rvt) {
|
||||||
visit::visit_expr(e, rcx, v);
|
visit::visit_expr(e, rcx, v);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_stmt(s: @ast::stmt, &&rcx: rcx, v: rvt) {
|
fn visit_stmt(s: @ast::stmt, &&rcx: @rcx, v: rvt) {
|
||||||
visit::visit_stmt(s, rcx, v);
|
visit::visit_stmt(s, rcx, v);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -114,37 +185,13 @@ fn visit_stmt(s: @ast::stmt, &&rcx: rcx, v: rvt) {
|
||||||
// references a region that is not in scope for that node. Returns
|
// references a region that is not in scope for that node. Returns
|
||||||
// false if an error is reported; this is used to cause us to cut off
|
// false if an error is reported; this is used to cause us to cut off
|
||||||
// region checking for that subtree to avoid reporting tons of errors.
|
// region checking for that subtree to avoid reporting tons of errors.
|
||||||
fn visit_node(id: ast::node_id, span: span, rcx: rcx) -> bool {
|
fn visit_node(id: ast::node_id, span: span, rcx: @rcx) -> bool {
|
||||||
let fcx = rcx.fcx;
|
let fcx = rcx.fcx;
|
||||||
|
|
||||||
// Try to resolve the type. If we encounter an error, then typeck
|
// Try to resolve the type. If we encounter an error, then typeck
|
||||||
// is going to fail anyway, so just stop here and let typeck
|
// is going to fail anyway, so just stop here and let typeck
|
||||||
// report errors later on in the writeback phase.
|
// report errors later on in the writeback phase.
|
||||||
//
|
let ty = alt rcx.resolve_node_type(id) {
|
||||||
// Note one important point: we do not attempt to resolve *region
|
|
||||||
// variables* here. This is because regionck is essentially adding
|
|
||||||
// constraints to those region variables and so may yet influence
|
|
||||||
// how they are resolved.
|
|
||||||
//
|
|
||||||
// Consider this silly example:
|
|
||||||
//
|
|
||||||
// fn borrow(x: &int) -> &int {x}
|
|
||||||
// fn foo(x: @int) -> int { /* block: B */
|
|
||||||
// let b = borrow(x); /* region: <R0> */
|
|
||||||
// *b
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// Here, the region of `b` will be `<R0>`. `<R0>` is constrainted
|
|
||||||
// to be some subregion of the block B and some superregion of
|
|
||||||
// the call. If we forced it now, we'd choose the smaller region
|
|
||||||
// (the call). But that would make the *b illegal. Since we don't
|
|
||||||
// resolve, the type of b will be `&<R0>.int` and then `*b` will require
|
|
||||||
// that `<R0>` be bigger than the let and the `*b` expression, so we
|
|
||||||
// will effectively resolve `<R0>` to be the block B.
|
|
||||||
let ty0 = fcx.node_ty(id);
|
|
||||||
let ty = alt resolve_type(fcx.infcx, ty0,
|
|
||||||
(resolve_all | force_all) -
|
|
||||||
(resolve_rvar | force_rvar)) {
|
|
||||||
result::err(_) { ret true; }
|
result::err(_) { ret true; }
|
||||||
result::ok(ty) { ty }
|
result::ok(ty) { ty }
|
||||||
};
|
};
|
||||||
|
@ -153,21 +200,29 @@ fn visit_node(id: ast::node_id, span: span, rcx: rcx) -> bool {
|
||||||
let tcx = fcx.ccx.tcx;
|
let tcx = fcx.ccx.tcx;
|
||||||
let encl_region = ty::encl_region(tcx, id);
|
let encl_region = ty::encl_region(tcx, id);
|
||||||
|
|
||||||
#debug["visit_node(ty=%s, id=%d, encl_region=%s, ty0=%s)",
|
#debug["visit_node(ty=%s, id=%d, encl_region=%s)",
|
||||||
ppaux::ty_to_str(tcx, ty),
|
ppaux::ty_to_str(tcx, ty),
|
||||||
id,
|
id,
|
||||||
ppaux::region_to_str(tcx, encl_region),
|
ppaux::region_to_str(tcx, encl_region)];
|
||||||
ppaux::ty_to_str(tcx, ty0)];
|
|
||||||
|
|
||||||
// Otherwise, look at the type and see if it is a region pointer.
|
// Otherwise, look at the type and see if it is a region pointer.
|
||||||
|
ret constrain_regions_in_type(rcx, encl_region, span, ty);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn constrain_regions_in_type(
|
||||||
|
rcx: @rcx,
|
||||||
|
encl_region: ty::region,
|
||||||
|
span: span,
|
||||||
|
ty: ty::t) -> bool {
|
||||||
|
|
||||||
let e = rcx.errors_reported;
|
let e = rcx.errors_reported;
|
||||||
ty::walk_regions_and_ty(
|
ty::walk_regions_and_ty(
|
||||||
tcx, ty,
|
rcx.fcx.ccx.tcx, ty,
|
||||||
|r| constrain_region(rcx, encl_region, span, r),
|
|r| constrain_region(rcx, encl_region, span, r),
|
||||||
|t| ty::type_has_regions(t));
|
|t| ty::type_has_regions(t));
|
||||||
ret (e == rcx.errors_reported);
|
ret (e == rcx.errors_reported);
|
||||||
|
|
||||||
fn constrain_region(rcx: rcx,
|
fn constrain_region(rcx: @rcx,
|
||||||
encl_region: ty::region,
|
encl_region: ty::region,
|
||||||
span: span,
|
span: span,
|
||||||
region: ty::region) {
|
region: ty::region) {
|
||||||
|
|
|
@ -64,7 +64,7 @@ fn lookup_vtable(fcx: @fn_ctxt, isc: resolve::iscopes, sp: span,
|
||||||
};
|
};
|
||||||
let ty = fixup_ty(fcx, sp, ty);
|
let ty = fixup_ty(fcx, sp, ty);
|
||||||
alt ty::get(ty).struct {
|
alt ty::get(ty).struct {
|
||||||
ty::ty_param(n, did) {
|
ty::ty_param({idx: n, def_id: did}) {
|
||||||
let mut n_bound = 0u;
|
let mut n_bound = 0u;
|
||||||
for vec::each(*tcx.ty_param_bounds.get(did.node)) |bound| {
|
for vec::each(*tcx.ty_param_bounds.get(did.node)) |bound| {
|
||||||
alt bound {
|
alt bound {
|
||||||
|
|
|
@ -69,7 +69,9 @@ fn collect_item_types(ccx: @crate_ctxt, crate: @ast::crate) {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl methods for @crate_ctxt {
|
impl methods for @crate_ctxt {
|
||||||
fn to_ty<RS: region_scope copy>(rs: RS, ast_ty: @ast::ty) -> ty::t {
|
fn to_ty<RS: region_scope copy owned>(
|
||||||
|
rs: RS, ast_ty: @ast::ty) -> ty::t {
|
||||||
|
|
||||||
ast_ty_to_ty(self, rs, ast_ty)
|
ast_ty_to_ty(self, rs, ast_ty)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -195,7 +195,7 @@ export resolve_type, resolve_region;
|
||||||
export resolve_borrowings;
|
export resolve_borrowings;
|
||||||
export methods; // for infer_ctxt
|
export methods; // for infer_ctxt
|
||||||
export unify_methods; // for infer_ctxt
|
export unify_methods; // for infer_ctxt
|
||||||
export fixup_err, fixup_err_to_str;
|
export fres, fixup_err, fixup_err_to_str;
|
||||||
export assignment;
|
export assignment;
|
||||||
export root, to_str;
|
export root, to_str;
|
||||||
export int_ty_set_all;
|
export int_ty_set_all;
|
||||||
|
@ -1789,7 +1789,7 @@ fn super_tys<C:combine>(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
(ty::ty_param(a_n, _), ty::ty_param(b_n, _)) if a_n == b_n {
|
(ty::ty_param(a_p), ty::ty_param(b_p)) if a_p.idx == b_p.idx {
|
||||||
ok(a)
|
ok(a)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -38,7 +38,7 @@ impl of region_scope for type_rscope {
|
||||||
}
|
}
|
||||||
|
|
||||||
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>(self: RS, r: ty::region)
|
fn in_anon_rscope<RS: region_scope copy owned>(self: RS, r: ty::region)
|
||||||
-> @anon_rscope {
|
-> @anon_rscope {
|
||||||
@anon_rscope({anon: r, base: self as region_scope})
|
@anon_rscope({anon: r, base: self as region_scope})
|
||||||
}
|
}
|
||||||
|
@ -52,7 +52,8 @@ impl of region_scope for @anon_rscope {
|
||||||
}
|
}
|
||||||
|
|
||||||
enum binding_rscope = {base: region_scope};
|
enum binding_rscope = {base: region_scope};
|
||||||
fn in_binding_rscope<RS: region_scope copy>(self: RS) -> @binding_rscope {
|
fn in_binding_rscope<RS: region_scope copy owned>(self: RS)
|
||||||
|
-> @binding_rscope {
|
||||||
let base = self as region_scope;
|
let base = self as region_scope;
|
||||||
@binding_rscope({base: base})
|
@binding_rscope({base: base})
|
||||||
}
|
}
|
||||||
|
|
|
@ -216,7 +216,7 @@ fn ty_to_str(cx: ctxt, typ: t) -> ~str {
|
||||||
}
|
}
|
||||||
ty_var(v) { v.to_str() }
|
ty_var(v) { v.to_str() }
|
||||||
ty_var_integral(v) { v.to_str() }
|
ty_var_integral(v) { v.to_str() }
|
||||||
ty_param(id, _) {
|
ty_param({idx: id, _}) {
|
||||||
~"'" + str::from_bytes(~[('a' as u8) + (id as u8)])
|
~"'" + str::from_bytes(~[('a' as u8) + (id as u8)])
|
||||||
}
|
}
|
||||||
ty_self { ~"self" }
|
ty_self { ~"self" }
|
||||||
|
|
|
@ -13,7 +13,7 @@ fn item_check(t: &tree) -> int {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn bottom_up_tree(arena: &a.arena::arena, item: int, depth: int) -> &a.tree {
|
fn bottom_up_tree(arena: &arena::arena, item: int, depth: int) -> &tree {
|
||||||
if depth > 0 {
|
if depth > 0 {
|
||||||
ret new(*arena) node(bottom_up_tree(arena, 2 * item - 1, depth - 1),
|
ret new(*arena) node(bottom_up_tree(arena, 2 * item - 1, depth - 1),
|
||||||
bottom_up_tree(arena, 2 * item, depth - 1),
|
bottom_up_tree(arena, 2 * item, depth - 1),
|
||||||
|
|
|
@ -3,7 +3,7 @@ fn to_lambda1(f: fn@(uint) -> uint) -> fn@(uint) -> uint {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn to_lambda2(b: fn(uint) -> uint) -> fn@(uint) -> uint {
|
fn to_lambda2(b: fn(uint) -> uint) -> fn@(uint) -> uint {
|
||||||
ret to_lambda1({|x| b(x)}); //~ ERROR not an owned value
|
ret to_lambda1({|x| b(x)}); //~ ERROR value may contain borrowed pointers
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
|
20
src/test/compile-fail/kindck-owned-trait-contains.rs
Normal file
20
src/test/compile-fail/kindck-owned-trait-contains.rs
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
iface repeat<A> { fn get() -> A; }
|
||||||
|
|
||||||
|
impl<A:copy> of repeat<A> for @A {
|
||||||
|
fn get() -> A { *self }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn repeater<A:copy>(v: @A) -> repeat<A> {
|
||||||
|
// Note: owned kind is not necessary as A appears in the iface type
|
||||||
|
v as repeat::<A> // No
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
// Here, an error results as the type of y is inferred to
|
||||||
|
// repeater<</3> where lt is the block.
|
||||||
|
let y = { //~ ERROR reference is not valid outside of its lifetime
|
||||||
|
let x = &3;
|
||||||
|
repeater(@x)
|
||||||
|
};
|
||||||
|
assert 3 == *(y.get()); //~ ERROR reference is not valid outside of its lifetime
|
||||||
|
}
|
35
src/test/compile-fail/kindck-owned-trait-scoped.rs
Normal file
35
src/test/compile-fail/kindck-owned-trait-scoped.rs
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
// A dummy iface/impl that work close over any type. The iface will
|
||||||
|
// be parameterized by a region due to the &self/int constraint.
|
||||||
|
|
||||||
|
iface foo {
|
||||||
|
fn foo(i: &self/int) -> int;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T:copy> of foo for T {
|
||||||
|
fn foo(i: &self/int) -> int {*i}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn to_foo<T:copy>(t: T) {
|
||||||
|
// This version is ok because, although T may contain borrowed
|
||||||
|
// pointers, it never escapes the fn body. We know this because
|
||||||
|
// the type of foo includes a region which will be resolved to
|
||||||
|
// the fn body itself.
|
||||||
|
let v = &3;
|
||||||
|
let x = {f:t} as foo;
|
||||||
|
assert x.foo(v) == 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn to_foo_2<T:copy>(t: T) -> foo {
|
||||||
|
// Not OK---T may contain borrowed ptrs and it is going to escape
|
||||||
|
// as part of the returned foo value
|
||||||
|
{f:t} as foo //~ ERROR value may contain borrowed pointers; use `owned` bound
|
||||||
|
}
|
||||||
|
|
||||||
|
fn to_foo_3<T:copy owned>(t: T) -> foo {
|
||||||
|
// OK---T may escape as part of the returned foo value, but it is
|
||||||
|
// owned and hence does not contain borrowed ptrs
|
||||||
|
{f:t} as foo
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
}
|
11
src/test/compile-fail/kindck-owned-trait.rs
Normal file
11
src/test/compile-fail/kindck-owned-trait.rs
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
iface foo { fn foo(); }
|
||||||
|
|
||||||
|
fn to_foo<T: copy foo>(t: T) -> foo {
|
||||||
|
t as foo //~ ERROR value may contain borrowed pointers; use `owned` bound
|
||||||
|
}
|
||||||
|
|
||||||
|
fn to_foo2<T: copy foo owned>(t: T) -> foo {
|
||||||
|
t as foo
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
|
@ -1,5 +1,5 @@
|
||||||
fn copy1<T: copy>(t: T) -> fn@() -> T {
|
fn copy1<T: copy>(t: T) -> fn@() -> T {
|
||||||
fn@() -> T { t } //~ ERROR not an owned value
|
fn@() -> T { t } //~ ERROR value may contain borrowed pointers
|
||||||
}
|
}
|
||||||
|
|
||||||
fn copy2<T: copy owned>(t: T) -> fn@() -> T {
|
fn copy2<T: copy owned>(t: T) -> fn@() -> T {
|
||||||
|
@ -8,12 +8,12 @@ fn copy2<T: copy owned>(t: T) -> fn@() -> T {
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let x = &3;
|
let x = &3;
|
||||||
copy2(&x); //~ ERROR instantiating a type parameter with an incompatible type
|
copy2(&x); //~ ERROR missing `owned`
|
||||||
|
|
||||||
copy2(@3);
|
copy2(@3);
|
||||||
copy2(@&x); //~ ERROR instantiating a type parameter with an incompatible type
|
copy2(@&x); //~ ERROR missing `owned`
|
||||||
|
|
||||||
copy2(fn@() {});
|
copy2(fn@() {});
|
||||||
copy2(fn~() {}); //~ WARNING instantiating copy type parameter with a not implicitly copyable type
|
copy2(fn~() {}); //~ WARNING instantiating copy type parameter with a not implicitly copyable type
|
||||||
copy2(fn&() {}); //~ ERROR instantiating a type parameter with an incompatible type
|
copy2(fn&() {}); //~ ERROR missing `copy owned`
|
||||||
}
|
}
|
||||||
|
|
10
src/test/run-pass/borrowck-borrow-from-at-vec.rs
Normal file
10
src/test/run-pass/borrowck-borrow-from-at-vec.rs
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
fn sum_slice(x: &[int]) -> int {
|
||||||
|
let mut sum = 0;
|
||||||
|
for x.each |i| { sum += i; }
|
||||||
|
ret sum;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let x = @[1, 2, 3];
|
||||||
|
assert sum_slice(x) == 6;
|
||||||
|
}
|
|
@ -1,7 +1,7 @@
|
||||||
iface hax { }
|
iface hax { }
|
||||||
impl <A> of hax for A { }
|
impl <A> of hax for A { }
|
||||||
|
|
||||||
fn perform_hax<T>(x: @T) -> hax {
|
fn perform_hax<T: owned>(x: @T) -> hax {
|
||||||
x as hax
|
x as hax
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
iface hax { }
|
iface hax { }
|
||||||
impl <A> of hax for A { }
|
impl <A> of hax for A { }
|
||||||
|
|
||||||
fn perform_hax<T>(x: @T) -> hax {
|
fn perform_hax<T: owned>(x: @T) -> hax {
|
||||||
x as hax
|
x as hax
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
16
src/test/run-pass/kindck-owned-trait-contains-1.rs
Normal file
16
src/test/run-pass/kindck-owned-trait-contains-1.rs
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
iface repeat<A> { fn get() -> A; }
|
||||||
|
|
||||||
|
impl<A:copy> of repeat<A> for @A {
|
||||||
|
fn get() -> A { *self }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn repeater<A:copy>(v: @A) -> repeat<A> {
|
||||||
|
// Note: owned kind is not necessary as A appears in the iface type
|
||||||
|
v as repeat::<A> // No
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let x = &3;
|
||||||
|
let y = repeater(@x);
|
||||||
|
assert *x == *(y.get());
|
||||||
|
}
|
|
@ -230,9 +230,9 @@ impl ptr_visitor<V: ty_visitor movable_ptr>
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_rptr(mtbl: uint, inner: *tydesc) -> bool {
|
fn visit_rptr(mtbl: uint, inner: *tydesc) -> bool {
|
||||||
self.align_to::<&static.u8>();
|
self.align_to::<&static/u8>();
|
||||||
if ! self.inner.visit_rptr(mtbl, inner) { ret false; }
|
if ! self.inner.visit_rptr(mtbl, inner) { ret false; }
|
||||||
self.bump_past::<&static.u8>();
|
self.bump_past::<&static/u8>();
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -268,9 +268,9 @@ impl ptr_visitor<V: ty_visitor movable_ptr>
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_evec_slice(mtbl: uint, inner: *tydesc) -> bool {
|
fn visit_evec_slice(mtbl: uint, inner: *tydesc) -> bool {
|
||||||
self.align_to::<&static.[u8]>();
|
self.align_to::<&static/[u8]>();
|
||||||
if ! self.inner.visit_evec_slice(mtbl, inner) { ret false; }
|
if ! self.inner.visit_evec_slice(mtbl, inner) { ret false; }
|
||||||
self.bump_past::<&static.[u8]>();
|
self.bump_past::<&static/[u8]>();
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -427,9 +427,9 @@ impl ptr_visitor<V: ty_visitor movable_ptr>
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_self() -> bool {
|
fn visit_self() -> bool {
|
||||||
self.align_to::<&static.u8>();
|
self.align_to::<&static/u8>();
|
||||||
if ! self.inner.visit_self() { ret false; }
|
if ! self.inner.visit_self() { ret false; }
|
||||||
self.align_to::<&static.u8>();
|
self.align_to::<&static/u8>();
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
fn f(x : &a.int) -> &a.int {
|
fn f(x : &a/int) -> &a/int {
|
||||||
ret &*x;
|
ret &*x;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
// A very limited test of the "bottom" region
|
// A very limited test of the "bottom" region
|
||||||
|
|
||||||
fn produce_static<T>() -> &static.T { fail; }
|
fn produce_static<T>() -> &static/T { fail; }
|
||||||
|
|
||||||
fn foo<T>(x: &T) -> &uint { produce_static() }
|
fn foo<T>(x: &T) -> &uint { produce_static() }
|
||||||
|
|
||||||
|
|
|
@ -8,14 +8,14 @@ fn ok(f: fn@(x: &uint)) {
|
||||||
// f's type should be a subtype of g's type), because f can be
|
// f's type should be a subtype of g's type), because f can be
|
||||||
// used in any context that expects g's type. But this currently
|
// used in any context that expects g's type. But this currently
|
||||||
// fails.
|
// fails.
|
||||||
let mut g: fn@(y: &r.uint) = fn@(x: &r.uint) { };
|
let mut g: fn@(y: &r/uint) = fn@(x: &r/uint) { };
|
||||||
g = f;
|
g = f;
|
||||||
}
|
}
|
||||||
|
|
||||||
// This version is the same as above, except that here, g's type is
|
// This version is the same as above, except that here, g's type is
|
||||||
// inferred.
|
// inferred.
|
||||||
fn ok_inferred(f: fn@(x: &uint)) {
|
fn ok_inferred(f: fn@(x: &uint)) {
|
||||||
let mut g = fn@(x: &r.uint) { };
|
let mut g = fn@(x: &r/uint) { };
|
||||||
g = f;
|
g = f;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,5 +19,8 @@ fn get_v(gc: get_ctxt) -> uint {
|
||||||
fn main() {
|
fn main() {
|
||||||
let ctxt = { v: 22u };
|
let ctxt = { v: 22u };
|
||||||
let hc = { c: &ctxt };
|
let hc = { c: &ctxt };
|
||||||
assert get_v(hc as get_ctxt) == 22u;
|
|
||||||
|
// 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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,12 +15,12 @@ type ccx = {
|
||||||
x: int
|
x: int
|
||||||
};
|
};
|
||||||
|
|
||||||
fn alloc(_bcx : &a.arena) -> &a.bcx unsafe {
|
fn alloc(_bcx : &arena) -> &bcx unsafe {
|
||||||
ret unsafe::reinterpret_cast(
|
ret unsafe::reinterpret_cast(
|
||||||
libc::malloc(sys::size_of::<bcx/&blk>() as libc::size_t));
|
libc::malloc(sys::size_of::<bcx/&blk>() as libc::size_t));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn h(bcx : &a.bcx) -> &a.bcx {
|
fn h(bcx : &bcx) -> &bcx {
|
||||||
ret alloc(bcx.fcx.arena);
|
ret alloc(bcx.fcx.arena);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
fn region_identity(x: &r.uint) -> &r.uint { x }
|
fn region_identity(x: &uint) -> &uint { x }
|
||||||
|
|
||||||
fn apply<T>(t: T, f: fn(T) -> T) -> T { f(t) }
|
fn apply<T>(t: T, f: fn(T) -> T) -> T { f(t) }
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue