Skip to content

Commit 6145757

Browse files
authored
Rollup merge of rust-lang#64852 - Baranowski:param_note_52082, r=estebank
Print ParamTy span when accessing a field (rust-lang#52082)
2 parents 69a3009 + 9ad99c3 commit 6145757

6 files changed

+188
-26
lines changed

src/librustc_typeck/check/expr.rs

+54-24
Original file line numberDiff line numberDiff line change
@@ -1394,30 +1394,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
13941394
} else if self.method_exists(field, expr_t, expr.hir_id, true) {
13951395
self.ban_take_value_of_method(expr, expr_t, field);
13961396
} else if !expr_t.is_primitive_ty() {
1397-
let mut err = self.no_such_field_err(field.span, field, expr_t);
1398-
1399-
match expr_t.kind {
1400-
ty::Adt(def, _) if !def.is_enum() => {
1401-
self.suggest_fields_on_recordish(&mut err, def, field);
1402-
}
1403-
ty::Array(_, len) => {
1404-
self.maybe_suggest_array_indexing(&mut err, expr, base, field, len);
1405-
}
1406-
ty::RawPtr(..) => {
1407-
self.suggest_first_deref_field(&mut err, expr, base, field);
1408-
}
1409-
_ => {}
1410-
}
1411-
1412-
if field.name == kw::Await {
1413-
// We know by construction that `<expr>.await` is either on Rust 2015
1414-
// or results in `ExprKind::Await`. Suggest switching the edition to 2018.
1415-
err.note("to `.await` a `Future`, switch to Rust 2018");
1416-
err.help("set `edition = \"2018\"` in `Cargo.toml`");
1417-
err.note("for more on editions, read https://doc.rust-lang.org/edition-guide");
1418-
}
1419-
1420-
err.emit();
1397+
self.ban_nonexisting_field(field, base, expr, expr_t);
14211398
} else {
14221399
type_error_struct!(
14231400
self.tcx().sess,
@@ -1433,6 +1410,42 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
14331410
self.tcx().types.err
14341411
}
14351412

1413+
fn ban_nonexisting_field(
1414+
&self,
1415+
field: ast::Ident,
1416+
base: &'tcx hir::Expr,
1417+
expr: &'tcx hir::Expr,
1418+
expr_t: Ty<'tcx>,
1419+
) {
1420+
let mut err = self.no_such_field_err(field.span, field, expr_t);
1421+
1422+
match expr_t.peel_refs().kind {
1423+
ty::Array(_, len) => {
1424+
self.maybe_suggest_array_indexing(&mut err, expr, base, field, len);
1425+
}
1426+
ty::RawPtr(..) => {
1427+
self.suggest_first_deref_field(&mut err, expr, base, field);
1428+
}
1429+
ty::Adt(def, _) if !def.is_enum() => {
1430+
self.suggest_fields_on_recordish(&mut err, def, field);
1431+
}
1432+
ty::Param(param_ty) => {
1433+
self.point_at_param_definition(&mut err, param_ty);
1434+
}
1435+
_ => {}
1436+
}
1437+
1438+
if field.name == kw::Await {
1439+
// We know by construction that `<expr>.await` is either on Rust 2015
1440+
// or results in `ExprKind::Await`. Suggest switching the edition to 2018.
1441+
err.note("to `.await` a `Future`, switch to Rust 2018");
1442+
err.help("set `edition = \"2018\"` in `Cargo.toml`");
1443+
err.note("for more on editions, read https://doc.rust-lang.org/edition-guide");
1444+
}
1445+
1446+
err.emit();
1447+
}
1448+
14361449
fn ban_private_field_access(
14371450
&self,
14381451
expr: &hir::Expr,
@@ -1495,6 +1508,23 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
14951508
err.emit();
14961509
}
14971510

1511+
fn point_at_param_definition(&self, err: &mut DiagnosticBuilder<'_>, param: ty::ParamTy) {
1512+
let generics = self.tcx.generics_of(self.body_id.owner_def_id());
1513+
let generic_param = generics.type_param(&param, self.tcx);
1514+
if let ty::GenericParamDefKind::Type{synthetic: Some(..), ..} = generic_param.kind {
1515+
return;
1516+
}
1517+
let param_def_id = generic_param.def_id;
1518+
let param_hir_id = match self.tcx.hir().as_local_hir_id(param_def_id) {
1519+
Some(x) => x,
1520+
None => return,
1521+
};
1522+
let param_span = self.tcx.hir().span(param_hir_id);
1523+
let param_name = self.tcx.hir().ty_param_name(param_hir_id);
1524+
1525+
err.span_label(param_span, &format!("type parameter '{}' declared here", param_name));
1526+
}
1527+
14981528
fn suggest_fields_on_recordish(
14991529
&self,
15001530
err: &mut DiagnosticBuilder<'_>,

src/test/ui/derived-errors/issue-30580.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ error[E0609]: no field `c` on type `&Foo`
22
--> $DIR/issue-30580.rs:12:11
33
|
44
LL | b.c;
5-
| ^
5+
| ^ help: a field with a similar name exists: `a`
66

77
error: aborting due to previous error
88

src/test/ui/issues/issue-31011.stderr

+3
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@ error[E0609]: no field `trace` on type `&T`
44
LL | if $ctx.trace {
55
| ^^^^^
66
...
7+
LL | fn wrap<T>(context: &T) -> ()
8+
| - type parameter 'T' declared here
9+
LL | {
710
LL | log!(context, "entered wrapper");
811
| --------------------------------- in this macro invocation
912

src/test/ui/structs/struct-pat-derived-error.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ error[E0609]: no field `d` on type `&A`
22
--> $DIR/struct-pat-derived-error.rs:8:31
33
|
44
LL | let A { x, y } = self.d;
5-
| ^
5+
| ^ help: a field with a similar name exists: `b`
66

77
error[E0026]: struct `A` does not have fields named `x`, `y`
88
--> $DIR/struct-pat-derived-error.rs:8:17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
// Fix issue 52082: Confusing error if accidentially defining a type paramter with the same name as
2+
// an existing type
3+
//
4+
// To this end, make sure that when trying to retrieve a field of a (reference to) type parameter,
5+
// rustc points to the point where the parameter was defined.
6+
#[derive(Debug)]
7+
struct Point
8+
{
9+
x: i32,
10+
y: i32
11+
}
12+
13+
impl Point
14+
{
15+
fn add(a: &Point, b: &Point) -> Point
16+
{
17+
Point {x: a.x + b.x, y: a.y + b.y}
18+
}
19+
}
20+
21+
trait Eq
22+
{
23+
fn equals_ref<T>(a: &T, b: &T) -> bool;
24+
fn equals_val<T>(a: T, b: T) -> bool;
25+
}
26+
27+
impl Eq for Point
28+
{
29+
fn equals_ref<Point>(a: &Point, b: &Point) -> bool
30+
{
31+
a.x == b.x && a.y == b.y //~ ERROR no field `x` on type `&Point` [E0609]
32+
//~|ERROR no field `x` on type `&Point` [E0609]
33+
//~|ERROR no field `y` on type `&Point` [E0609]
34+
//~|ERROR no field `y` on type `&Point` [E0609]
35+
}
36+
37+
fn equals_val<Point>(a: Point, b: Point) -> bool
38+
{
39+
a.x == b.x && a.y == b.y //~ ERROR no field `x` on type `Point` [E0609]
40+
//~|ERROR no field `x` on type `Point` [E0609]
41+
//~|ERROR no field `y` on type `Point` [E0609]
42+
//~|ERROR no field `y` on type `Point` [E0609]
43+
}
44+
}
45+
46+
fn main()
47+
{
48+
let p1 = Point {x: 0, y: 10};
49+
let p2 = Point {x: 20, y: 42};
50+
println!("{:?}", Point::add(&p1, &p2));
51+
println!("p1: {:?}, p2: {:?}", p1, p2);
52+
println!("&p1 == &p2: {:?}", Point::equals_ref(&p1, &p2));
53+
println!("p1 == p2: {:?}", Point::equals_val(p1, p2));
54+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
error[E0609]: no field `x` on type `&Point`
2+
--> $DIR/issue-52082-type-param-shadows-existing-type.rs:31:11
3+
|
4+
LL | fn equals_ref<Point>(a: &Point, b: &Point) -> bool
5+
| ----- type parameter 'Point' declared here
6+
LL | {
7+
LL | a.x == b.x && a.y == b.y
8+
| ^
9+
10+
error[E0609]: no field `x` on type `&Point`
11+
--> $DIR/issue-52082-type-param-shadows-existing-type.rs:31:18
12+
|
13+
LL | fn equals_ref<Point>(a: &Point, b: &Point) -> bool
14+
| ----- type parameter 'Point' declared here
15+
LL | {
16+
LL | a.x == b.x && a.y == b.y
17+
| ^
18+
19+
error[E0609]: no field `y` on type `&Point`
20+
--> $DIR/issue-52082-type-param-shadows-existing-type.rs:31:25
21+
|
22+
LL | fn equals_ref<Point>(a: &Point, b: &Point) -> bool
23+
| ----- type parameter 'Point' declared here
24+
LL | {
25+
LL | a.x == b.x && a.y == b.y
26+
| ^
27+
28+
error[E0609]: no field `y` on type `&Point`
29+
--> $DIR/issue-52082-type-param-shadows-existing-type.rs:31:32
30+
|
31+
LL | fn equals_ref<Point>(a: &Point, b: &Point) -> bool
32+
| ----- type parameter 'Point' declared here
33+
LL | {
34+
LL | a.x == b.x && a.y == b.y
35+
| ^
36+
37+
error[E0609]: no field `x` on type `Point`
38+
--> $DIR/issue-52082-type-param-shadows-existing-type.rs:39:11
39+
|
40+
LL | fn equals_val<Point>(a: Point, b: Point) -> bool
41+
| ----- type parameter 'Point' declared here
42+
LL | {
43+
LL | a.x == b.x && a.y == b.y
44+
| ^
45+
46+
error[E0609]: no field `x` on type `Point`
47+
--> $DIR/issue-52082-type-param-shadows-existing-type.rs:39:18
48+
|
49+
LL | fn equals_val<Point>(a: Point, b: Point) -> bool
50+
| ----- type parameter 'Point' declared here
51+
LL | {
52+
LL | a.x == b.x && a.y == b.y
53+
| ^
54+
55+
error[E0609]: no field `y` on type `Point`
56+
--> $DIR/issue-52082-type-param-shadows-existing-type.rs:39:25
57+
|
58+
LL | fn equals_val<Point>(a: Point, b: Point) -> bool
59+
| ----- type parameter 'Point' declared here
60+
LL | {
61+
LL | a.x == b.x && a.y == b.y
62+
| ^
63+
64+
error[E0609]: no field `y` on type `Point`
65+
--> $DIR/issue-52082-type-param-shadows-existing-type.rs:39:32
66+
|
67+
LL | fn equals_val<Point>(a: Point, b: Point) -> bool
68+
| ----- type parameter 'Point' declared here
69+
LL | {
70+
LL | a.x == b.x && a.y == b.y
71+
| ^
72+
73+
error: aborting due to 8 previous errors
74+
75+
For more information about this error, try `rustc --explain E0609`.

0 commit comments

Comments
 (0)