Skip to content

Commit 921393c

Browse files
committed
Change the self def_id to a self_info in typeck, and inherit
That is, treat `self` as if it has dynamic scope. This seems to be harmless, and prevents an ICE as per #3563
1 parent fb9458e commit 921393c

File tree

5 files changed

+248
-8
lines changed

5 files changed

+248
-8
lines changed

src/librustc/middle/typeck/check/mod.rs

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -178,7 +178,10 @@ pub struct fn_ctxt {
178178
// var_bindings, locals and next_var_id are shared
179179
// with any nested functions that capture the environment
180180
// (and with any functions whose environment is being captured).
181-
self_impl_def_id: Option<ast::def_id>,
181+
182+
// Refers to whichever `self` is in scope, even this fn_ctxt is
183+
// for a nested closure that captures `self`
184+
self_info: Option<self_info>,
182185
ret_ty: ty::t,
183186
// Used by loop bodies that return from the outer function
184187
indirect_ret_ty: Option<ty::t>,
@@ -227,7 +230,7 @@ fn blank_fn_ctxt(ccx: @crate_ctxt, rty: ty::t,
227230
// It's kind of a kludge to manufacture a fake function context
228231
// and statement context, but we might as well do write the code only once
229232
@fn_ctxt {
230-
self_impl_def_id: None,
233+
self_info: None,
231234
ret_ty: rty,
232235
indirect_ret_ty: None,
233236
purity: ast::pure_fn,
@@ -320,7 +323,7 @@ fn check_fn(ccx: @crate_ctxt,
320323
} else { None };
321324

322325
@fn_ctxt {
323-
self_impl_def_id: self_info.map(|self_info| self_info.def_id),
326+
self_info: self_info,
324327
ret_ty: ret_ty,
325328
indirect_ret_ty: indirect_ret_ty,
326329
purity: purity,
@@ -1553,7 +1556,9 @@ fn check_expr_with_unifier(fcx: @fn_ctxt,
15531556

15541557
fcx.write_ty(expr.id, fty);
15551558

1556-
check_fn(fcx.ccx, None, &fn_ty, decl, body,
1559+
// We inherit the same self info as the enclosing scope,
1560+
// since the function we're checking might capture `self`
1561+
check_fn(fcx.ccx, fcx.self_info, &fn_ty, decl, body,
15571562
fn_kind, Some(fcx));
15581563
}
15591564

src/librustc/middle/typeck/infer/mod.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -737,15 +737,16 @@ impl infer_ctxt {
737737
fn type_error_message(sp: span, mk_msg: fn(~str) -> ~str,
738738
actual_ty: ty::t, err: Option<&ty::type_err>) {
739739
let actual_ty = self.resolve_type_vars_if_possible(actual_ty);
740+
let mut actual_sty = ty::get(copy actual_ty);
740741

741742
// Don't report an error if actual type is ty_err.
742-
match ty::get(actual_ty).sty {
743+
match actual_sty.sty {
743744
ty::ty_err => return,
744745
// Should really not report an error if the type
745746
// has ty_err anywhere as a component, but that's
746747
// annoying since we haven't written a visitor for
747748
// ty::t yet
748-
ty::ty_fn(fty) => match ty::get(fty.sig.output).sty {
749+
ty::ty_fn(ref fty) => match ty::get(fty.sig.output).sty {
749750
ty::ty_err => return,
750751
_ => ()
751752
},

src/test/run-pass/issue-3563.rs renamed to src/test/compile-fail/issue-3563.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,9 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11-
// xfail-test
1211
trait A {
1312
fn a(&self) {
14-
|| self.b()
13+
|| self.b() //~ ERROR type `&self/self` does not implement any method in scope named `b`
1514
}
1615
}
16+
fn main() {}

src/test/run-pass/issue-3563-2.rs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
#[allow(default_methods)]
12+
trait Canvas {
13+
fn add_point(point: &int);
14+
fn add_points(shapes: &[int]) {
15+
for shapes.each |pt| {
16+
self.add_point(pt)
17+
}
18+
}
19+
20+
}
21+
22+
fn main() {}

src/test/run-pass/issue-3563-3.rs

Lines changed: 212 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,212 @@
1+
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// ASCII art shape renderer.
12+
// Demonstrates traits, impls, operator overloading, non-copyable struct, unit testing.
13+
// To run execute: rustc --test shapes.rs && ./shapes
14+
15+
// Rust's core library is tightly bound to the language itself so it is automatically linked in.
16+
// However the std library is designed to be optional (for code that must run on constrained
17+
// environments like embedded devices or special environments like kernel code) so it must
18+
// be explicitly linked in.
19+
extern mod std;
20+
21+
// Extern mod controls linkage. Use controls the visibility of names to modules that are
22+
// already linked in. Using WriterUtil allows us to use the write_line method.
23+
use io::WriterUtil;
24+
25+
// Represents a position on a canvas.
26+
struct Point
27+
{
28+
x: int,
29+
y: int,
30+
}
31+
32+
// Represents an offset on a canvas. (This has the same structure as a Point.
33+
// but different semantics).
34+
struct Size
35+
{
36+
width: int,
37+
height: int,
38+
}
39+
40+
struct Rect
41+
{
42+
top_left: Point,
43+
size: Size,
44+
}
45+
46+
// TODO: operators
47+
48+
// Contains the information needed to do shape rendering via ASCII art.
49+
struct AsciiArt
50+
{
51+
width: uint,
52+
height: uint,
53+
priv fill: char,
54+
priv lines: ~[~[mut char]],
55+
56+
// This struct can be quite large so we'll disable copying: developers need
57+
// to either pass these structs around via borrowed pointers or move them.
58+
drop {}
59+
}
60+
61+
// It's common to define a constructor sort of function to create struct instances.
62+
// If there is a canonical constructor it is typically named the same as the type.
63+
// Other constructor sort of functions are typically named from_foo, from_bar, etc.
64+
fn AsciiArt(width: uint, height: uint, fill: char) -> AsciiArt
65+
{
66+
// Use an anonymous function to build a vector of vectors containing
67+
// blank characters for each position in our canvas.
68+
let lines = do vec::build_sized(height)
69+
|push|
70+
{
71+
for height.times
72+
{
73+
let mut line = ~[];
74+
vec::grow_set(&mut line, width-1, &'.', '.');
75+
push(vec::to_mut(line));
76+
}
77+
};
78+
79+
// Rust code often returns values by omitting the trailing semi-colon
80+
// instead of using an explicit return statement.
81+
AsciiArt {width: width, height: height, fill: fill, lines: lines}
82+
}
83+
84+
// Methods particular to the AsciiArt struct.
85+
impl AsciiArt
86+
{
87+
fn add_pt(x: int, y: int)
88+
{
89+
if x >= 0 && x < self.width as int
90+
{
91+
if y >= 0 && y < self.height as int
92+
{
93+
// Note that numeric types don't implicitly convert to each other.
94+
let v = y as uint;
95+
let h = x as uint;
96+
97+
// Vector subscripting will normally copy the element, but &v[i]
98+
// will return a reference which is what we need because the
99+
// element is:
100+
// 1) potentially large
101+
// 2) needs to be modified
102+
let row = &self.lines[v];
103+
row[h] = self.fill;
104+
}
105+
}
106+
}
107+
}
108+
109+
// Allows AsciiArt to be converted to a string using the libcore ToStr trait.
110+
// Note that the %s fmt! specifier will not call this automatically.
111+
impl AsciiArt : ToStr
112+
{
113+
pure fn to_str() -> ~str
114+
{
115+
// Convert each line into a string.
116+
let lines = do self.lines.map |line| {str::from_chars(*line)};
117+
118+
// Concatenate the lines together using a new-line.
119+
str::connect(lines, "\n")
120+
}
121+
}
122+
123+
// This is similar to an interface in other languages: it defines a protocol which
124+
// developers can implement for arbitrary concrete types.
125+
#[allow(default_methods)]
126+
trait Canvas
127+
{
128+
fn add_point(shape: Point);
129+
fn add_rect(shape: Rect);
130+
131+
// Unlike interfaces traits support default implementations.
132+
// Got an ICE as soon as I added this method.
133+
fn add_points(shapes: &[Point])
134+
{
135+
for shapes.each |pt| {self.add_point(*pt)};
136+
}
137+
}
138+
139+
// Here we provide an implementation of the Canvas methods for AsciiArt.
140+
// Other implementations could also be provided (e.g. for PDF or Apple's Quartz)
141+
// and code can use them polymorphically via the Canvas trait.
142+
impl AsciiArt : Canvas
143+
{
144+
fn add_point(shape: Point)
145+
{
146+
self.add_pt(shape.x, shape.y);
147+
}
148+
149+
fn add_rect(shape: Rect)
150+
{
151+
// Add the top and bottom lines.
152+
for int::range(shape.top_left.x, shape.top_left.x + shape.size.width)
153+
|x|
154+
{
155+
self.add_pt(x, shape.top_left.y);
156+
self.add_pt(x, shape.top_left.y + shape.size.height - 1);
157+
}
158+
159+
// Add the left and right lines.
160+
for int::range(shape.top_left.y, shape.top_left.y + shape.size.height)
161+
|y|
162+
{
163+
self.add_pt(shape.top_left.x, y);
164+
self.add_pt(shape.top_left.x + shape.size.width - 1, y);
165+
}
166+
}
167+
}
168+
169+
// Rust's unit testing framework is currently a bit under-developed so we'll use
170+
// this little helper.
171+
pub fn check_strs(actual: &str, expected: &str) -> bool
172+
{
173+
if actual != expected
174+
{
175+
io::stderr().write_line(fmt!("Found:\n%s\nbut expected\n%s", actual, expected));
176+
return false;
177+
}
178+
return true;
179+
}
180+
181+
182+
fn test_ascii_art_ctor()
183+
{
184+
let art = AsciiArt(3, 3, '*');
185+
assert check_strs(art.to_str(), "...\n...\n...");
186+
}
187+
188+
189+
fn test_add_pt()
190+
{
191+
let art = AsciiArt(3, 3, '*');
192+
art.add_pt(0, 0);
193+
art.add_pt(0, -10);
194+
art.add_pt(1, 2);
195+
assert check_strs(art.to_str(), "*..\n...\n.*.");
196+
}
197+
198+
199+
fn test_shapes()
200+
{
201+
let art = AsciiArt(4, 4, '*');
202+
art.add_rect(Rect {top_left: Point {x: 0, y: 0}, size: Size {width: 4, height: 4}});
203+
art.add_point(Point {x: 2, y: 2});
204+
assert check_strs(art.to_str(), "****\n*..*\n*.**\n****");
205+
}
206+
207+
fn main() {
208+
test_ascii_art_ctor();
209+
test_add_pt();
210+
test_shapes();
211+
}
212+

0 commit comments

Comments
 (0)