Skip to content

Commit

Permalink
Print ParamTy span when accessing a field (rust-lang#52082)
Browse files Browse the repository at this point in the history
  • Loading branch information
Baranowski authored and andjo403 committed Oct 3, 2019
1 parent 77b0b82 commit df00987
Show file tree
Hide file tree
Showing 3 changed files with 184 additions and 3 deletions.
34 changes: 31 additions & 3 deletions src/librustc_typeck/check/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1397,9 +1397,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let mut err = self.no_such_field_err(field.span, field, expr_t);

match expr_t.kind {
ty::Adt(def, _) if !def.is_enum() => {
self.suggest_fields_on_recordish(&mut err, def, field);
}
ty::Array(_, len) => {
self.maybe_suggest_array_indexing(&mut err, expr, base, field, len);
}
Expand All @@ -1409,6 +1406,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
_ => {}
}

let deref_t = match expr_t.kind {
ty::Ref(_, ref_t, _) => ref_t,
_ => &expr_t
};
match deref_t.kind {
ty::Adt(def, _) if !def.is_enum() => {
self.suggest_fields_on_recordish(&mut err, def, field);
}
ty::Param(param_ty) => {
self.explain_param(&mut err, param_ty);
}
_ => {}
}

if field.name == kw::Await {
// We know by construction that `<expr>.await` is either on Rust 2015
// or results in `ExprKind::Await`. Suggest switching the edition to 2018.
Expand Down Expand Up @@ -1495,6 +1506,23 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
err.emit();
}

fn explain_param(
&self,
err: &mut DiagnosticBuilder<'_>,
param: ty::ParamTy,
) {
let generics = self.tcx.generics_of(self.body_id.owner_def_id());
let param_def_id = generics.type_param(&param, self.tcx).def_id;
let param_hir_id = match self.tcx.hir().as_local_hir_id(param_def_id) {
Some(x) => x,
None => return,
};
let param_span = self.tcx.hir().span(param_hir_id);
let param_name = self.tcx.hir().ty_param_name(param_hir_id);

err.span_note(param_span, &format!("Type parameter '{}' was declared here", param_name));
}

fn suggest_fields_on_recordish(
&self,
err: &mut DiagnosticBuilder<'_>,
Expand Down
54 changes: 54 additions & 0 deletions src/test/ui/typeck/issue-52082.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
// Fix issue 52082: Confusing error if accidentially defining a type paramter with the same name as
// an existing type
//
// To this end, make sure that when trying to retrieve a field of a (reference to) type parameter,
// rustc points to the point where the parameter was defined.
#[derive(Debug)]
struct Point
{
x: i32,
y: i32
}

impl Point
{
fn add(a: &Point, b: &Point) -> Point
{
Point {x: a.x + b.x, y: a.y + b.y}
}
}

trait Eq
{
fn equals_ref<T>(a: &T, b: &T) -> bool;
fn equals_val<T>(a: T, b: T) -> bool;
}

impl Eq for Point
{
fn equals_ref<Point>(a: &Point, b: &Point) -> bool
{
a.x == b.x && a.y == b.y //~ ERROR no field `x` on type `&Point` [E0609]
//~|ERROR no field `x` on type `&Point` [E0609]
//~|ERROR no field `y` on type `&Point` [E0609]
//~|ERROR no field `y` on type `&Point` [E0609]
}

fn equals_val<Point>(a: Point, b: Point) -> bool
{
a.x == b.x && a.y == b.y //~ ERROR no field `x` on type `Point` [E0609]
//~|ERROR no field `x` on type `Point` [E0609]
//~|ERROR no field `y` on type `Point` [E0609]
//~|ERROR no field `y` on type `Point` [E0609]
}
}

fn main()
{
let p1 = Point {x: 0, y: 10};
let p2 = Point {x: 20, y: 42};
println!("{:?}", Point::add(&p1, &p2));
println!("p1: {:?}, p2: {:?}", p1, p2);
println!("&p1 == &p2: {:?}", Point::equals_ref(&p1, &p2));
println!("p1 == p2: {:?}", Point::equals_val(p1, p2));
}
99 changes: 99 additions & 0 deletions src/test/ui/typeck/issue-52082.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
error[E0609]: no field `x` on type `&Point`
--> $DIR/issue-52082.rs:31:11
|
LL | a.x == b.x && a.y == b.y
| ^
|
note: Type parameter 'Point' was declared here
--> $DIR/issue-52082.rs:29:19
|
LL | fn equals_ref<Point>(a: &Point, b: &Point) -> bool
| ^^^^^

error[E0609]: no field `x` on type `&Point`
--> $DIR/issue-52082.rs:31:18
|
LL | a.x == b.x && a.y == b.y
| ^
|
note: Type parameter 'Point' was declared here
--> $DIR/issue-52082.rs:29:19
|
LL | fn equals_ref<Point>(a: &Point, b: &Point) -> bool
| ^^^^^

error[E0609]: no field `y` on type `&Point`
--> $DIR/issue-52082.rs:31:25
|
LL | a.x == b.x && a.y == b.y
| ^
|
note: Type parameter 'Point' was declared here
--> $DIR/issue-52082.rs:29:19
|
LL | fn equals_ref<Point>(a: &Point, b: &Point) -> bool
| ^^^^^

error[E0609]: no field `y` on type `&Point`
--> $DIR/issue-52082.rs:31:32
|
LL | a.x == b.x && a.y == b.y
| ^
|
note: Type parameter 'Point' was declared here
--> $DIR/issue-52082.rs:29:19
|
LL | fn equals_ref<Point>(a: &Point, b: &Point) -> bool
| ^^^^^

error[E0609]: no field `x` on type `Point`
--> $DIR/issue-52082.rs:39:11
|
LL | a.x == b.x && a.y == b.y
| ^
|
note: Type parameter 'Point' was declared here
--> $DIR/issue-52082.rs:37:19
|
LL | fn equals_val<Point>(a: Point, b: Point) -> bool
| ^^^^^

error[E0609]: no field `x` on type `Point`
--> $DIR/issue-52082.rs:39:18
|
LL | a.x == b.x && a.y == b.y
| ^
|
note: Type parameter 'Point' was declared here
--> $DIR/issue-52082.rs:37:19
|
LL | fn equals_val<Point>(a: Point, b: Point) -> bool
| ^^^^^

error[E0609]: no field `y` on type `Point`
--> $DIR/issue-52082.rs:39:25
|
LL | a.x == b.x && a.y == b.y
| ^
|
note: Type parameter 'Point' was declared here
--> $DIR/issue-52082.rs:37:19
|
LL | fn equals_val<Point>(a: Point, b: Point) -> bool
| ^^^^^

error[E0609]: no field `y` on type `Point`
--> $DIR/issue-52082.rs:39:32
|
LL | a.x == b.x && a.y == b.y
| ^
|
note: Type parameter 'Point' was declared here
--> $DIR/issue-52082.rs:37:19
|
LL | fn equals_val<Point>(a: Point, b: Point) -> bool
| ^^^^^

error: aborting due to 8 previous errors

For more information about this error, try `rustc --explain E0609`.

0 comments on commit df00987

Please sign in to comment.