Skip to content

Commit 4f105e4

Browse files
committed
In resolve, visit the path in an iface ref
Necessary to resolve any type arguments in a ref to a parameterized iface. This meant that, for example: class A implements B<int> { ... didn't work before, because the "int" in B's argument wasn't getting visited, and thus wasn't getting resolved. Now it works. Partially addresses Issue #2288, but I also want to check that class ty params can appear as the type arguments to ifaces (for example, class A<T> implements B<T> {... should work.)
1 parent 1226669 commit 4f105e4

File tree

6 files changed

+109
-12
lines changed

6 files changed

+109
-12
lines changed

src/rustc/middle/kind.rs

+10
Original file line numberDiff line numberDiff line change
@@ -242,6 +242,9 @@ fn check_expr(e: @expr, cx: ctx, v: visit::vt<ctx>) {
242242
ty::ty_class(parent_id, ts) {
243243
/* ...and if it has a class type, prepend the
244244
class bounds onto the method bounds */
245+
/* n.b. this code is very likely sketchy --
246+
currently, class-impl-very-parameterized-iface
247+
fails here and is thus xfailed */
245248
bounds =
246249
@(*ty::lookup_item_type(cx.tcx, parent_id).bounds
247250
+ *bounds);
@@ -260,6 +263,13 @@ fn check_expr(e: @expr, cx: ctx, v: visit::vt<ctx>) {
260263
}
261264
}
262265
};
266+
if vec::len(ts) != vec::len(*bounds) {
267+
// Fail earlier to make debugging easier
268+
fail #fmt("Internal error: in kind::check_expr, length \
269+
mismatch between actual and declared bounds: actual = \
270+
%s (%u tys), declared = %s (%u tys)", ts, ts.len(),
271+
*bounds, bounds.len());
272+
}
263273
vec::iter2(ts, *bounds) {|ty, bound|
264274
check_bounds(cx, e.span, ty, bound)
265275
}

src/rustc/middle/resolve.rs

+19-9
Original file line numberDiff line numberDiff line change
@@ -430,17 +430,17 @@ fn resolve_names(e: @env, c: @ast::crate) {
430430

431431
fn walk_item(e: @env, i: @ast::item, sc: scopes, v: vt<scopes>) {
432432
visit_item_with_scope(e, i, sc, v);
433-
/*
434-
Resolve the ifaces that a class implements; do nothing for
435-
non-class items
436-
*/
437433
alt i.node {
438-
ast::item_class(_, ifaces, _, _, _) {
439-
/* visit the iface paths... */
440-
for ifaces.each {|p| resolve_iface_ref(p, sc, e) ;}
441-
}
434+
/* At this point, the code knows what ifaces the iface refs
435+
refer to, so it's possible to resolve them.
436+
*/
442437
ast::item_impl(_, _, ifce, _, _) {
443-
ifce.iter { |p| resolve_iface_ref(p, sc, e); }
438+
ifce.iter {|p| resolve_iface_ref(p, sc, e);}
439+
}
440+
ast::item_class(_, ifaces, _, _, _) {
441+
for ifaces.each {|p|
442+
resolve_iface_ref(p, sc, e);
443+
}
444444
}
445445
_ {}
446446
}
@@ -529,6 +529,10 @@ fn resolve_names(e: @env, c: @ast::crate) {
529529

530530

531531
// Visit helper functions
532+
/*
533+
This is used in more than one context, thus should only call generic
534+
visit methods. Called both from map_crate and resolve_names.
535+
*/
532536
fn visit_item_with_scope(e: @env, i: @ast::item, sc: scopes, v: vt<scopes>) {
533537
// Some magic here. Items with the !resolve_unexported attribute
534538
// cause us to consider every name to be exported when resolving their
@@ -567,6 +571,12 @@ fn visit_item_with_scope(e: @env, i: @ast::item, sc: scopes, v: vt<scopes>) {
567571
/* visit the constructor... */
568572
let ctor_scope = cons(scope_method(ctor.node.self_id, tps),
569573
@class_scope);
574+
/*
575+
but, I should visit the ifaces refs in the class scope, no?
576+
*/
577+
for ifaces.each {|p|
578+
visit::visit_path(p.path, class_scope, v);
579+
}
570580
visit_fn_with_scope(e, visit::fk_item_fn(i.ident, tps), ctor.node.dec,
571581
ctor.node.body, ctor.span, ctor.node.id,
572582
ctor_scope, v);

src/rustc/middle/ty.rs

+1-2
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,7 @@ import metadata::csearch;
1212
import util::common::*;
1313
import util::ppaux::region_to_str;
1414
import util::ppaux::vstore_to_str;
15-
import util::ppaux::ty_to_str;
16-
import util::ppaux::ty_constr_to_str;
15+
import util::ppaux::{ty_to_str, tys_to_str, ty_constr_to_str};
1716
import syntax::print::pprust::*;
1817

1918
export ty_vid, region_vid, vid;

src/rustc/middle/typeck.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import result::{result, extensions};
22
import syntax::{ast, ast_util};
33
import ast::spanned;
4+
import ast_map::node_id_to_str;
45
import syntax::ast_util::{local_def, respan, split_class_items};
56
import syntax::visit;
67
import metadata::csearch;
@@ -12,7 +13,7 @@ import middle::ty;
1213
import middle::ty::{arg, field, node_type_table, mk_nil,
1314
ty_param_bounds_and_ty, lookup_public_fields};
1415
import middle::ty::{ty_vid, region_vid, vid};
15-
import util::ppaux::{ty_to_str, region_to_str,
16+
import util::ppaux::{ty_to_str, tys_to_str, region_to_str,
1617
bound_region_to_str, vstore_to_str};
1718
import std::smallintmap;
1819
import std::smallintmap::map;
@@ -1639,6 +1640,8 @@ mod collect {
16391640
let fty = ty::mk_fn(tcx, mty.fty);
16401641
tcx.tcache.insert(
16411642
local_def(m.id),
1643+
// n.b. This code is kind of sketchy (concat'ing i_bounds
1644+
// with bounds), but removing *i_bounds breaks other stuff
16421645
{bounds: @(*i_bounds + *bounds), rp: rp, ty: fty});
16431646
write_ty_to_tcx(tcx, m.id, fty);
16441647
{mty: mty, id: m.id, span: m.span}

src/rustc/util/ppaux.rs

+6
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,12 @@ fn vstore_to_str(cx: ctxt, vs: ty::vstore) -> str {
8484
}
8585
}
8686

87+
fn tys_to_str(cx: ctxt, ts: [t]) -> str {
88+
let mut rs = "";
89+
for ts.each {|t| rs += ty_to_str(cx, t); }
90+
rs
91+
}
92+
8793
fn ty_to_str(cx: ctxt, typ: t) -> str {
8894
fn fn_input_to_str(cx: ctxt, input: {mode: ast::mode, ty: t}) ->
8995
str {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
// xfail-fast
2+
use std;
3+
import std::map::*;
4+
5+
class cat implements map<int, bool> {
6+
priv {
7+
// Yes, you can have negative meows
8+
let mut meows : int;
9+
fn meow() {
10+
self.meows += 1;
11+
#error("Meow %d", self.meows);
12+
if self.meows % 5 == 0 {
13+
self.how_hungry += 1;
14+
}
15+
}
16+
}
17+
18+
let mut how_hungry : int;
19+
let name : str;
20+
21+
new(in_x : int, in_y : int, in_name: str)
22+
{ self.meows = in_x; self.how_hungry = in_y; self.name = in_name; }
23+
24+
fn speak() { self.meow(); }
25+
26+
fn eat() -> bool {
27+
if self.how_hungry > 0 {
28+
#error("OM NOM NOM");
29+
self.how_hungry -= 2;
30+
ret true;
31+
}
32+
else {
33+
#error("Not hungry!");
34+
ret false;
35+
}
36+
}
37+
38+
fn size() -> uint { self.meows as uint }
39+
fn insert(&&k: int, &&v: bool) -> bool {
40+
if v { self.meows += k; } else { self.meows -= k; };
41+
true
42+
}
43+
fn contains_key(&&k: int) -> bool { k <= self.meows }
44+
fn get(&&k:int) -> bool { k <= self.meows }
45+
fn find(&&k:int) -> option<bool> { some(self.get(k)) }
46+
fn remove(&&k:int) -> option<bool> { self.meows -= k; some(true) }
47+
fn each(f: fn(&&int, &&bool) -> bool) {
48+
let mut n = int::abs(self.meows);
49+
while n > 0 {
50+
if !f(n, true) { break; }
51+
n -= 1;
52+
}
53+
}
54+
fn each_key(&&f: fn(&&int) -> bool) {
55+
for self.each {|k, _v| if !f(k) { break; } cont;};
56+
}
57+
fn each_value(&&f: fn(&&bool) -> bool) {
58+
for self.each {|_k, v| if !f(v) { break; } cont;};
59+
}
60+
}
61+
62+
fn main() {
63+
let nyan : cat = cat(0, 2, "nyan");
64+
uint::range(1u, 5u) {|_i| nyan.speak(); }
65+
// cat returns true if uint input is greater than
66+
// the number of meows so far
67+
assert(nyan.get(1));
68+
assert(!nyan.get(10));
69+
}

0 commit comments

Comments
 (0)