mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-23 23:34:48 +00:00
Make self
visible when typechecking nested functions
Necessary to allow supertrait methods to be called in default methods. r=nikomatsakis
This commit is contained in:
parent
2d1ce01a8a
commit
80435ad429
@ -282,8 +282,9 @@ impl LookupContext {
|
||||
ty_self => {
|
||||
// Call is of the form "self.foo()" and appears in one
|
||||
// of a trait's default method implementations.
|
||||
let self_did = self.fcx.self_impl_def_id.expect(
|
||||
~"unexpected `none` for self_impl_def_id");
|
||||
let self_did = self.fcx.self_info.expect(
|
||||
~"self_impl_def_id is undefined (`self` may not \
|
||||
be in scope here").def_id;
|
||||
let substs = {self_r: None, self_ty: None, tps: ~[]};
|
||||
self.push_inherent_candidates_from_self(
|
||||
self_ty, self_did, &substs);
|
||||
|
@ -178,7 +178,10 @@ pub 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>,
|
||||
|
||||
// Refers to whichever `self` is in scope, even this fn_ctxt is
|
||||
// for a nested closure that captures `self`
|
||||
self_info: Option<self_info>,
|
||||
ret_ty: ty::t,
|
||||
// Used by loop bodies that return from the outer function
|
||||
indirect_ret_ty: Option<ty::t>,
|
||||
@ -227,7 +230,7 @@ fn blank_fn_ctxt(ccx: @crate_ctxt, rty: ty::t,
|
||||
// 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,
|
||||
self_info: None,
|
||||
ret_ty: rty,
|
||||
indirect_ret_ty: None,
|
||||
purity: ast::pure_fn,
|
||||
@ -320,7 +323,7 @@ fn check_fn(ccx: @crate_ctxt,
|
||||
} else { None };
|
||||
|
||||
@fn_ctxt {
|
||||
self_impl_def_id: self_info.map(|self_info| self_info.def_id),
|
||||
self_info: self_info,
|
||||
ret_ty: ret_ty,
|
||||
indirect_ret_ty: indirect_ret_ty,
|
||||
purity: purity,
|
||||
@ -1553,7 +1556,9 @@ fn check_expr_with_unifier(fcx: @fn_ctxt,
|
||||
|
||||
fcx.write_ty(expr.id, fty);
|
||||
|
||||
check_fn(fcx.ccx, None, &fn_ty, decl, body,
|
||||
// We inherit the same self info as the enclosing scope,
|
||||
// since the function we're checking might capture `self`
|
||||
check_fn(fcx.ccx, fcx.self_info, &fn_ty, decl, body,
|
||||
fn_kind, Some(fcx));
|
||||
}
|
||||
|
||||
|
@ -8,9 +8,9 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// xfail-test
|
||||
trait A {
|
||||
fn a(&self) {
|
||||
|| self.b()
|
||||
|| self.b() //~ ERROR type `&self/self` does not implement any method in scope named `b`
|
||||
}
|
||||
}
|
||||
fn main() {}
|
22
src/test/run-pass/issue-3563-2.rs
Normal file
22
src/test/run-pass/issue-3563-2.rs
Normal file
@ -0,0 +1,22 @@
|
||||
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#[allow(default_methods)]
|
||||
trait Canvas {
|
||||
fn add_point(point: &int);
|
||||
fn add_points(shapes: &[int]) {
|
||||
for shapes.each |pt| {
|
||||
self.add_point(pt)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fn main() {}
|
212
src/test/run-pass/issue-3563-3.rs
Normal file
212
src/test/run-pass/issue-3563-3.rs
Normal file
@ -0,0 +1,212 @@
|
||||
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// ASCII art shape renderer.
|
||||
// Demonstrates traits, impls, operator overloading, non-copyable struct, unit testing.
|
||||
// To run execute: rustc --test shapes.rs && ./shapes
|
||||
|
||||
// Rust's core library is tightly bound to the language itself so it is automatically linked in.
|
||||
// However the std library is designed to be optional (for code that must run on constrained
|
||||
// environments like embedded devices or special environments like kernel code) so it must
|
||||
// be explicitly linked in.
|
||||
extern mod std;
|
||||
|
||||
// Extern mod controls linkage. Use controls the visibility of names to modules that are
|
||||
// already linked in. Using WriterUtil allows us to use the write_line method.
|
||||
use io::WriterUtil;
|
||||
|
||||
// Represents a position on a canvas.
|
||||
struct Point
|
||||
{
|
||||
x: int,
|
||||
y: int,
|
||||
}
|
||||
|
||||
// Represents an offset on a canvas. (This has the same structure as a Point.
|
||||
// but different semantics).
|
||||
struct Size
|
||||
{
|
||||
width: int,
|
||||
height: int,
|
||||
}
|
||||
|
||||
struct Rect
|
||||
{
|
||||
top_left: Point,
|
||||
size: Size,
|
||||
}
|
||||
|
||||
// TODO: operators
|
||||
|
||||
// Contains the information needed to do shape rendering via ASCII art.
|
||||
struct AsciiArt
|
||||
{
|
||||
width: uint,
|
||||
height: uint,
|
||||
priv fill: char,
|
||||
priv lines: ~[~[mut char]],
|
||||
|
||||
// This struct can be quite large so we'll disable copying: developers need
|
||||
// to either pass these structs around via borrowed pointers or move them.
|
||||
drop {}
|
||||
}
|
||||
|
||||
// It's common to define a constructor sort of function to create struct instances.
|
||||
// If there is a canonical constructor it is typically named the same as the type.
|
||||
// Other constructor sort of functions are typically named from_foo, from_bar, etc.
|
||||
fn AsciiArt(width: uint, height: uint, fill: char) -> AsciiArt
|
||||
{
|
||||
// Use an anonymous function to build a vector of vectors containing
|
||||
// blank characters for each position in our canvas.
|
||||
let lines = do vec::build_sized(height)
|
||||
|push|
|
||||
{
|
||||
for height.times
|
||||
{
|
||||
let mut line = ~[];
|
||||
vec::grow_set(&mut line, width-1, &'.', '.');
|
||||
push(vec::to_mut(line));
|
||||
}
|
||||
};
|
||||
|
||||
// Rust code often returns values by omitting the trailing semi-colon
|
||||
// instead of using an explicit return statement.
|
||||
AsciiArt {width: width, height: height, fill: fill, lines: lines}
|
||||
}
|
||||
|
||||
// Methods particular to the AsciiArt struct.
|
||||
impl AsciiArt
|
||||
{
|
||||
fn add_pt(x: int, y: int)
|
||||
{
|
||||
if x >= 0 && x < self.width as int
|
||||
{
|
||||
if y >= 0 && y < self.height as int
|
||||
{
|
||||
// Note that numeric types don't implicitly convert to each other.
|
||||
let v = y as uint;
|
||||
let h = x as uint;
|
||||
|
||||
// Vector subscripting will normally copy the element, but &v[i]
|
||||
// will return a reference which is what we need because the
|
||||
// element is:
|
||||
// 1) potentially large
|
||||
// 2) needs to be modified
|
||||
let row = &self.lines[v];
|
||||
row[h] = self.fill;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Allows AsciiArt to be converted to a string using the libcore ToStr trait.
|
||||
// Note that the %s fmt! specifier will not call this automatically.
|
||||
impl AsciiArt : ToStr
|
||||
{
|
||||
pure fn to_str() -> ~str
|
||||
{
|
||||
// Convert each line into a string.
|
||||
let lines = do self.lines.map |line| {str::from_chars(*line)};
|
||||
|
||||
// Concatenate the lines together using a new-line.
|
||||
str::connect(lines, "\n")
|
||||
}
|
||||
}
|
||||
|
||||
// This is similar to an interface in other languages: it defines a protocol which
|
||||
// developers can implement for arbitrary concrete types.
|
||||
#[allow(default_methods)]
|
||||
trait Canvas
|
||||
{
|
||||
fn add_point(shape: Point);
|
||||
fn add_rect(shape: Rect);
|
||||
|
||||
// Unlike interfaces traits support default implementations.
|
||||
// Got an ICE as soon as I added this method.
|
||||
fn add_points(shapes: &[Point])
|
||||
{
|
||||
for shapes.each |pt| {self.add_point(*pt)};
|
||||
}
|
||||
}
|
||||
|
||||
// Here we provide an implementation of the Canvas methods for AsciiArt.
|
||||
// Other implementations could also be provided (e.g. for PDF or Apple's Quartz)
|
||||
// and code can use them polymorphically via the Canvas trait.
|
||||
impl AsciiArt : Canvas
|
||||
{
|
||||
fn add_point(shape: Point)
|
||||
{
|
||||
self.add_pt(shape.x, shape.y);
|
||||
}
|
||||
|
||||
fn add_rect(shape: Rect)
|
||||
{
|
||||
// Add the top and bottom lines.
|
||||
for int::range(shape.top_left.x, shape.top_left.x + shape.size.width)
|
||||
|x|
|
||||
{
|
||||
self.add_pt(x, shape.top_left.y);
|
||||
self.add_pt(x, shape.top_left.y + shape.size.height - 1);
|
||||
}
|
||||
|
||||
// Add the left and right lines.
|
||||
for int::range(shape.top_left.y, shape.top_left.y + shape.size.height)
|
||||
|y|
|
||||
{
|
||||
self.add_pt(shape.top_left.x, y);
|
||||
self.add_pt(shape.top_left.x + shape.size.width - 1, y);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Rust's unit testing framework is currently a bit under-developed so we'll use
|
||||
// this little helper.
|
||||
pub fn check_strs(actual: &str, expected: &str) -> bool
|
||||
{
|
||||
if actual != expected
|
||||
{
|
||||
io::stderr().write_line(fmt!("Found:\n%s\nbut expected\n%s", actual, expected));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
fn test_ascii_art_ctor()
|
||||
{
|
||||
let art = AsciiArt(3, 3, '*');
|
||||
assert check_strs(art.to_str(), "...\n...\n...");
|
||||
}
|
||||
|
||||
|
||||
fn test_add_pt()
|
||||
{
|
||||
let art = AsciiArt(3, 3, '*');
|
||||
art.add_pt(0, 0);
|
||||
art.add_pt(0, -10);
|
||||
art.add_pt(1, 2);
|
||||
assert check_strs(art.to_str(), "*..\n...\n.*.");
|
||||
}
|
||||
|
||||
|
||||
fn test_shapes()
|
||||
{
|
||||
let art = AsciiArt(4, 4, '*');
|
||||
art.add_rect(Rect {top_left: Point {x: 0, y: 0}, size: Size {width: 4, height: 4}});
|
||||
art.add_point(Point {x: 2, y: 2});
|
||||
assert check_strs(art.to_str(), "****\n*..*\n*.**\n****");
|
||||
}
|
||||
|
||||
fn main() {
|
||||
test_ascii_art_ctor();
|
||||
test_add_pt();
|
||||
test_shapes();
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user