Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

rustc: Better resolve errors for *T, &T, &mut T, Box<T> #14265

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 39 additions & 18 deletions src/librustc/middle/resolve.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4891,6 +4891,25 @@ impl<'a> Resolver<'a> {
}

fn find_fallback_in_self_type(&mut self, name: Name) -> FallbackSuggestion {
#[deriving(Eq)]
enum FallbackChecks {
Everything,
OnlyTraitAndStatics
}

fn extract_path_and_node_id(t: &Ty, allow: FallbackChecks)
-> Option<(Path, NodeId, FallbackChecks)> {
match t.node {
TyPath(ref path, _, node_id) => Some((path.clone(), node_id, allow)),
TyPtr(mut_ty) => extract_path_and_node_id(mut_ty.ty, OnlyTraitAndStatics),
TyRptr(_, mut_ty) => extract_path_and_node_id(mut_ty.ty, allow),
// This doesn't handle the remaining `Ty` variants as they are not
// that commonly the self_type, it might be interesting to provide
// support for those in future.
_ => None,
}
}

fn get_module(this: &mut Resolver, span: Span, ident_path: &[ast::Ident])
-> Option<Rc<Module>> {
let root = this.current_module.clone();
Expand Down Expand Up @@ -4918,27 +4937,29 @@ impl<'a> Resolver<'a> {
}
}

let (path, node_id) = match self.current_self_type {
Some(ref ty) => match ty.node {
TyPath(ref path, _, node_id) => (path.clone(), node_id),
_ => unreachable!(),
let (path, node_id, allowed) = match self.current_self_type {
Some(ref ty) => match extract_path_and_node_id(ty, Everything) {
Some(x) => x,
None => return NoSuggestion,
},
None => return NoSuggestion,
};

// Look for a field with the same name in the current self_type.
match self.def_map.borrow().find(&node_id) {
Some(&DefTy(did))
| Some(&DefStruct(did))
| Some(&DefVariant(_, did, _)) => match self.structs.find(&did) {
None => {}
Some(fields) => {
if fields.iter().any(|&field_name| name == field_name) {
return Field;
if allowed == Everything {
// Look for a field with the same name in the current self_type.
match self.def_map.borrow().find(&node_id) {
Some(&DefTy(did))
| Some(&DefStruct(did))
| Some(&DefVariant(_, did, _)) => match self.structs.find(&did) {
None => {}
Some(fields) => {
if fields.iter().any(|&field_name| name == field_name) {
return Field;
}
}
}
},
_ => {} // Self type didn't resolve properly
},
_ => {} // Self type didn't resolve properly
}
}

let ident_path = path.segments.iter().map(|seg| seg.identifier).collect::<Vec<_>>();
Expand All @@ -4955,8 +4976,8 @@ impl<'a> Resolver<'a> {
FromTrait(_) => unreachable!()
}
}
Some(DefMethod(_, None)) => return Method,
Some(DefMethod(_, _)) => return TraitMethod,
Some(DefMethod(_, None)) if allowed == Everything => return Method,
Some(DefMethod(_, Some(_))) => return TraitMethod,
_ => ()
}
}
Expand Down
113 changes: 113 additions & 0 deletions src/test/compile-fail/issue-14254.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
// Copyright 2014 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.

trait Foo {
fn bar(&self);
fn baz(&self) { }
fn bah(_: Option<Self>) { }
}

struct BarTy {
x : int,
y : f64,
}

impl BarTy {
fn a() {}
fn b(&self) {}
}

impl Foo for *BarTy {
fn bar(&self) {
baz();
//~^ ERROR: unresolved name `baz`. Did you mean to call `self.baz`?
a;
//~^ ERROR: unresolved name `a`. Did you mean to call `BarTy::a`?
}
}

impl<'a> Foo for &'a BarTy {
fn bar(&self) {
baz();
//~^ ERROR: unresolved name `baz`. Did you mean to call `self.baz`?
x;
//~^ ERROR: unresolved name `x`. Did you mean `self.x`?
y;
//~^ ERROR: unresolved name `y`. Did you mean `self.y`?
a;
//~^ ERROR: unresolved name `a`. Did you mean to call `BarTy::a`?
bah;
//~^ ERROR: unresolved name `bah`. Did you mean to call `Foo::bah`?
b;
//~^ ERROR: unresolved name `b`. Did you mean to call `self.b`?
}
}

impl<'a> Foo for &'a mut BarTy {
fn bar(&self) {
baz();
//~^ ERROR: unresolved name `baz`. Did you mean to call `self.baz`?
x;
//~^ ERROR: unresolved name `x`. Did you mean `self.x`?
y;
//~^ ERROR: unresolved name `y`. Did you mean `self.y`?
a;
//~^ ERROR: unresolved name `a`. Did you mean to call `BarTy::a`?
bah;
//~^ ERROR: unresolved name `bah`. Did you mean to call `Foo::bah`?
b;
//~^ ERROR: unresolved name `b`. Did you mean to call `self.b`?
}
}

impl Foo for Box<BarTy> {
fn bar(&self) {
baz();
//~^ ERROR: unresolved name `baz`. Did you mean to call `self.baz`?
bah;
//~^ ERROR: unresolved name `bah`. Did you mean to call `Foo::bah`?
}
}

impl Foo for *int {
fn bar(&self) {
baz();
//~^ ERROR: unresolved name `baz`. Did you mean to call `self.baz`?
bah;
//~^ ERROR: unresolved name `bah`. Did you mean to call `Foo::bah`?
}
}

impl<'a> Foo for &'a int {
fn bar(&self) {
baz();
//~^ ERROR: unresolved name `baz`. Did you mean to call `self.baz`?
bah;
//~^ ERROR: unresolved name `bah`. Did you mean to call `Foo::bah`?
}
}

impl<'a> Foo for &'a mut int {
fn bar(&self) {
baz();
//~^ ERROR: unresolved name `baz`. Did you mean to call `self.baz`?
bah;
//~^ ERROR: unresolved name `bah`. Did you mean to call `Foo::bah`?
}
}

impl Foo for Box<int> {
fn bar(&self) {
baz();
//~^ ERROR: unresolved name `baz`. Did you mean to call `self.baz`?
bah;
//~^ ERROR: unresolved name `bah`. Did you mean to call `Foo::bah`?
}
}
100 changes: 100 additions & 0 deletions src/test/run-pass/issue-14254.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
// Copyright 2014 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.

trait Foo {
fn bar(&self);
fn baz(&self) { }
fn bah(_: Option<Self>) { }
}

struct BarTy {
x : int,
y : f64,
}

impl BarTy {
fn a() {}
fn b(&self) {}
}

// If these fail, it's necessary to update middle::resolve and the cfail tests.
impl Foo for *BarTy {
fn bar(&self) {
self.baz();
BarTy::a();
Foo::bah(None::<*BarTy>);
}
}

// If these fail, it's necessary to update middle::resolve and the cfail tests.
impl<'a> Foo for &'a BarTy {
fn bar(&self) {
self.baz();
self.x;
self.y;
BarTy::a();
Foo::bah(None::<&BarTy>);
self.b();
}
}

// If these fail, it's necessary to update middle::resolve and the cfail tests.
impl<'a> Foo for &'a mut BarTy {
fn bar(&self) {
self.baz();
self.x;
self.y;
BarTy::a();
Foo::bah(None::<&mut BarTy>);
self.b();
}
}

// If these fail, it's necessary to update middle::resolve and the cfail tests.
impl Foo for Box<BarTy> {
fn bar(&self) {
self.baz();
Foo::bah(None::<Box<BarTy>>);
}
}

// If these fail, it's necessary to update middle::resolve and the cfail tests.
impl Foo for *int {
fn bar(&self) {
self.baz();
Foo::bah(None::<*int>);
}
}

// If these fail, it's necessary to update middle::resolve and the cfail tests.
impl<'a> Foo for &'a int {
fn bar(&self) {
self.baz();
Foo::bah(None::<&int>);
}
}

// If these fail, it's necessary to update middle::resolve and the cfail tests.
impl<'a> Foo for &'a mut int {
fn bar(&self) {
self.baz();
Foo::bah(None::<&mut int>);
}
}

// If these fail, it's necessary to update middle::resolve and the cfail tests.
impl Foo for Box<int> {
fn bar(&self) {
self.baz();
Foo::bah(None::<Box<int>>);
}
}

fn main() {}