Skip to content

Commit 97520cc

Browse files
committed
Auto merge of #47116 - estebank:non-accessible-ctor, r=petrochenkov
Tweaks to invalid ctor messages - Do not suggest using a constructor that isn't accessible - Suggest the appropriate syntax (`()`/`{}` as appropriate) - Add note when trying to use `Self` as a ctor CC #22488, fix #47085.
2 parents 3001ab1 + 0674050 commit 97520cc

14 files changed

+466
-116
lines changed

src/librustc_resolve/lib.rs

+30-18
Original file line numberDiff line numberDiff line change
@@ -898,7 +898,7 @@ impl<'a> LexicalScopeBinding<'a> {
898898
}
899899
}
900900

901-
#[derive(Clone)]
901+
#[derive(Clone, Debug)]
902902
enum PathResult<'a> {
903903
Module(Module<'a>),
904904
NonModule(PathResolution),
@@ -2568,7 +2568,8 @@ impl<'a> Resolver<'a> {
25682568
let code = source.error_code(def.is_some());
25692569
let (base_msg, fallback_label, base_span) = if let Some(def) = def {
25702570
(format!("expected {}, found {} `{}`", expected, def.kind_name(), path_str),
2571-
format!("not a {}", expected), span)
2571+
format!("not a {}", expected),
2572+
span)
25722573
} else {
25732574
let item_str = path[path.len() - 1].node;
25742575
let item_span = path[path.len() - 1].span;
@@ -2585,7 +2586,8 @@ impl<'a> Resolver<'a> {
25852586
(mod_prefix, format!("`{}`", names_to_string(mod_path)))
25862587
};
25872588
(format!("cannot find {} `{}` in {}{}", expected, item_str, mod_prefix, mod_str),
2588-
format!("not found in {}", mod_str), item_span)
2589+
format!("not found in {}", mod_str),
2590+
item_span)
25892591
};
25902592
let code = DiagnosticId::Error(code.into());
25912593
let mut err = this.session.struct_span_err_with_code(base_span, &base_msg, code);
@@ -2700,20 +2702,37 @@ impl<'a> Resolver<'a> {
27002702
}
27012703
return (err, candidates);
27022704
},
2703-
_ if ns == ValueNS && is_struct_like(def) => {
2704-
if let Def::Struct(def_id) = def {
2705-
if let Some((ctor_def, ctor_vis))
2706-
= this.struct_constructors.get(&def_id).cloned() {
2707-
if is_expected(ctor_def) && !this.is_accessible(ctor_vis) {
2708-
err.span_label(span, format!("constructor is not visible \
2709-
here due to private fields"));
2710-
}
2705+
(Def::Struct(def_id), _) if ns == ValueNS => {
2706+
if let Some((ctor_def, ctor_vis))
2707+
= this.struct_constructors.get(&def_id).cloned() {
2708+
let accessible_ctor = this.is_accessible(ctor_vis);
2709+
if is_expected(ctor_def) && !accessible_ctor {
2710+
err.span_label(span, format!("constructor is not visible \
2711+
here due to private fields"));
27112712
}
2713+
} else {
2714+
err.span_label(span, format!("did you mean `{} {{ /* fields */ }}`?",
2715+
path_str));
27122716
}
2717+
return (err, candidates);
2718+
}
2719+
(Def::Union(..), _) |
2720+
(Def::Variant(..), _) |
2721+
(Def::VariantCtor(_, CtorKind::Fictive), _) if ns == ValueNS => {
27132722
err.span_label(span, format!("did you mean `{} {{ /* fields */ }}`?",
27142723
path_str));
27152724
return (err, candidates);
27162725
}
2726+
(Def::SelfTy(..), _) if ns == ValueNS => {
2727+
err.span_label(span, fallback_label);
2728+
err.note("can't use `Self` as a constructor, you must use the \
2729+
implemented struct");
2730+
return (err, candidates);
2731+
}
2732+
(Def::TyAlias(_), _) | (Def::AssociatedTy(..), _) if ns == ValueNS => {
2733+
err.note("can't use a type alias as a constructor");
2734+
return (err, candidates);
2735+
}
27172736
_ => {}
27182737
}
27192738
}
@@ -3965,13 +3984,6 @@ impl<'a> Resolver<'a> {
39653984
}
39663985
}
39673986

3968-
fn is_struct_like(def: Def) -> bool {
3969-
match def {
3970-
Def::VariantCtor(_, CtorKind::Fictive) => true,
3971-
_ => PathSource::Struct.is_expected(def),
3972-
}
3973-
}
3974-
39753987
fn is_self_type(path: &[SpannedIdent], namespace: Namespace) -> bool {
39763988
namespace == TypeNS && path.len() == 1 && path[0].node.name == keywords::SelfType.name()
39773989
}

src/librustc_typeck/check/callee.rs

+24-10
Original file line numberDiff line numberDiff line change
@@ -210,15 +210,25 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
210210
}
211211
}
212212
}
213-
let mut err = type_error_struct!(self.tcx.sess, call_expr.span, callee_ty, E0618,
214-
"expected function, found `{}`",
215-
if let Some(ref path) = unit_variant {
216-
path.to_string()
217-
} else {
218-
callee_ty.to_string()
219-
});
220-
if let Some(path) = unit_variant {
221-
err.help(&format!("did you mean to write `{}`?", path));
213+
214+
let mut err = type_error_struct!(
215+
self.tcx.sess,
216+
call_expr.span,
217+
callee_ty,
218+
E0618,
219+
"expected function, found {}",
220+
match unit_variant {
221+
Some(ref path) => format!("enum variant `{}`", path),
222+
None => format!("`{}`", callee_ty),
223+
});
224+
225+
err.span_label(call_expr.span, "not a function");
226+
227+
if let Some(ref path) = unit_variant {
228+
err.span_suggestion(call_expr.span,
229+
&format!("`{}` is a unit variant, you need to write it \
230+
without the parenthesis", path),
231+
path.to_string());
222232
}
223233

224234
if let hir::ExprCall(ref expr, _) = call_expr.node {
@@ -235,7 +245,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
235245
_ => self.tcx.hir.span_if_local(def.def_id())
236246
};
237247
if let Some(span) = def_span {
238-
err.span_note(span, "defined here");
248+
let name = match unit_variant {
249+
Some(path) => path,
250+
None => callee_ty.to_string(),
251+
};
252+
err.span_label(span, format!("`{}` defined here", name));
239253
}
240254
}
241255

src/librustc_typeck/check/compare_method.rs

+5-3
Original file line numberDiff line numberDiff line change
@@ -518,7 +518,10 @@ fn compare_self_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
518518
self_descr);
519519
err.span_label(impl_m_span, format!("`{}` used in impl", self_descr));
520520
if let Some(span) = tcx.hir.span_if_local(trait_m.def_id) {
521-
err.span_label(span, format!("trait declared without `{}`", self_descr));
521+
err.span_label(span, format!("trait method declared without `{}`", self_descr));
522+
} else {
523+
err.note_trait_signature(trait_m.name.to_string(),
524+
trait_m.signature(&tcx));
522525
}
523526
err.emit();
524527
return Err(ErrorReported);
@@ -533,8 +536,7 @@ fn compare_self_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
533536
not in the impl",
534537
trait_m.name,
535538
self_descr);
536-
err.span_label(impl_m_span,
537-
format!("expected `{}` in impl", self_descr));
539+
err.span_label(impl_m_span, format!("expected `{}` in impl", self_descr));
538540
if let Some(span) = tcx.hir.span_if_local(trait_m.def_id) {
539541
err.span_label(span, format!("`{}` used in trait", self_descr));
540542
} else {

src/test/compile-fail/E0185.rs

+5-3
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,16 @@
99
// except according to those terms.
1010

1111
trait Foo {
12-
fn foo(); //~ trait declared without `&self`
12+
fn foo();
13+
//~^ NOTE trait method declared without `&self`
1314
}
1415

1516
struct Bar;
1617

1718
impl Foo for Bar {
18-
fn foo(&self) {} //~ ERROR E0185
19-
//~^ `&self` used in impl
19+
fn foo(&self) {}
20+
//~^ ERROR E0185
21+
//~| NOTE `&self` used in impl
2022
}
2123

2224
fn main() {

src/test/compile-fail/E0618.rs

+4-2
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,9 @@ enum X {
1313
}
1414

1515
fn main() {
16-
X::Entry(); //~ ERROR expected function, found `X::Entry` [E0618]
16+
X::Entry();
17+
//~^ ERROR expected function, found enum variant `X::Entry` [E0618]
1718
let x = 0i32;
18-
x(); //~ ERROR expected function, found `i32` [E0618]
19+
x();
20+
//~^ ERROR expected function, found `i32` [E0618]
1921
}

src/test/ui/block-result/issue-20862.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ error[E0618]: expected function, found `()`
1313
--> $DIR/issue-20862.rs:17:13
1414
|
1515
17 | let x = foo(5)(2);
16-
| ^^^^^^^^^
16+
| ^^^^^^^^^ not a function
1717

1818
error: aborting due to 2 previous errors
1919

src/test/ui/empty-struct-unit-expr.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,8 @@ enum E {
2424
fn main() {
2525
let e2 = Empty2(); //~ ERROR expected function, found `Empty2`
2626
let e4 = E::Empty4();
27-
//~^ ERROR expected function, found `E::Empty4` [E0618]
27+
//~^ ERROR expected function, found enum variant `E::Empty4` [E0618]
2828
let xe2 = XEmpty2(); //~ ERROR expected function, found `empty_struct::XEmpty2`
2929
let xe4 = XE::XEmpty4();
30-
//~^ ERROR expected function, found `XE::XEmpty4` [E0618]
30+
//~^ ERROR expected function, found enum variant `XE::XEmpty4` [E0618]
3131
}
+18-19
Original file line numberDiff line numberDiff line change
@@ -1,41 +1,40 @@
11
error[E0618]: expected function, found `Empty2`
22
--> $DIR/empty-struct-unit-expr.rs:25:14
33
|
4-
25 | let e2 = Empty2(); //~ ERROR expected function, found `Empty2`
5-
| ^^^^^^^^
6-
|
7-
note: defined here
8-
--> $DIR/empty-struct-unit-expr.rs:18:1
9-
|
104
18 | struct Empty2;
11-
| ^^^^^^^^^^^^^^
5+
| -------------- `Empty2` defined here
6+
...
7+
25 | let e2 = Empty2(); //~ ERROR expected function, found `Empty2`
8+
| ^^^^^^^^ not a function
129

13-
error[E0618]: expected function, found `E::Empty4`
10+
error[E0618]: expected function, found enum variant `E::Empty4`
1411
--> $DIR/empty-struct-unit-expr.rs:26:14
1512
|
13+
21 | Empty4
14+
| ------ `E::Empty4` defined here
15+
...
1616
26 | let e4 = E::Empty4();
17-
| ^^^^^^^^^^^
18-
|
19-
= help: did you mean to write `E::Empty4`?
20-
note: defined here
21-
--> $DIR/empty-struct-unit-expr.rs:21:5
17+
| ^^^^^^^^^^^ not a function
18+
help: `E::Empty4` is a unit variant, you need to write it without the parenthesis
2219
|
23-
21 | Empty4
24-
| ^^^^^^
20+
26 | let e4 = E::Empty4;
21+
| ^^^^^^^^^
2522

2623
error[E0618]: expected function, found `empty_struct::XEmpty2`
2724
--> $DIR/empty-struct-unit-expr.rs:28:15
2825
|
2926
28 | let xe2 = XEmpty2(); //~ ERROR expected function, found `empty_struct::XEmpty2`
30-
| ^^^^^^^^^
27+
| ^^^^^^^^^ not a function
3128

32-
error[E0618]: expected function, found `XE::XEmpty4`
29+
error[E0618]: expected function, found enum variant `XE::XEmpty4`
3330
--> $DIR/empty-struct-unit-expr.rs:29:15
3431
|
3532
29 | let xe4 = XE::XEmpty4();
36-
| ^^^^^^^^^^^^^
33+
| ^^^^^^^^^^^^^ not a function
34+
help: `XE::XEmpty4` is a unit variant, you need to write it without the parenthesis
3735
|
38-
= help: did you mean to write `XE::XEmpty4`?
36+
29 | let xe4 = XE::XEmpty4;
37+
| ^^^^^^^^^^^
3938

4039
error: aborting due to 4 previous errors
4140

src/test/ui/issue-10969.stderr

+6-14
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,18 @@
11
error[E0618]: expected function, found `i32`
22
--> $DIR/issue-10969.rs:12:5
33
|
4-
12 | i(); //~ERROR expected function, found `i32`
5-
| ^^^
6-
|
7-
note: defined here
8-
--> $DIR/issue-10969.rs:11:9
9-
|
104
11 | fn func(i: i32) {
11-
| ^
5+
| - `i32` defined here
6+
12 | i(); //~ERROR expected function, found `i32`
7+
| ^^^ not a function
128

139
error[E0618]: expected function, found `i32`
1410
--> $DIR/issue-10969.rs:16:5
1511
|
16-
16 | i(); //~ERROR expected function, found `i32`
17-
| ^^^
18-
|
19-
note: defined here
20-
--> $DIR/issue-10969.rs:15:9
21-
|
2212
15 | let i = 0i32;
23-
| ^
13+
| - `i32` defined here
14+
16 | i(); //~ERROR expected function, found `i32`
15+
| ^^^ not a function
2416

2517
error: aborting due to 2 previous errors
2618

+81
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
// Copyright 2016 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+
mod m {
12+
pub enum E {
13+
Fn(u8),
14+
Struct {
15+
s: u8,
16+
},
17+
Unit,
18+
}
19+
20+
pub mod n {
21+
pub(in m) enum Z {
22+
Fn(u8),
23+
Struct {
24+
s: u8,
25+
},
26+
Unit,
27+
}
28+
}
29+
30+
use m::n::Z; // OK, only the type is imported
31+
32+
fn f() {
33+
n::Z;
34+
//~^ ERROR expected value, found enum `n::Z`
35+
Z;
36+
//~^ ERROR expected value, found enum `Z`
37+
let _: Z = Z::Fn;
38+
//~^ ERROR mismatched types
39+
let _: Z = Z::Struct;
40+
//~^ ERROR expected value, found struct variant `Z::Struct`
41+
let _ = Z::Unit();
42+
//~^ ERROR expected function, found enum variant `Z::Unit`
43+
let _ = Z::Unit {};
44+
// This is ok, it is equivalent to not having braces
45+
}
46+
}
47+
48+
use m::E; // OK, only the type is imported
49+
50+
fn main() {
51+
let _: E = m::E;
52+
//~^ ERROR expected value, found enum `m::E`
53+
let _: E = m::E::Fn;
54+
//~^ ERROR mismatched types
55+
let _: E = m::E::Struct;
56+
//~^ ERROR expected value, found struct variant `m::E::Struct`
57+
let _: E = m::E::Unit();
58+
//~^ ERROR expected function, found enum variant `m::E::Unit`
59+
let _: E = E;
60+
//~^ ERROR expected value, found enum `E`
61+
let _: E = E::Fn;
62+
//~^ ERROR mismatched types
63+
let _: E = E::Struct;
64+
//~^ ERROR expected value, found struct variant `E::Struct`
65+
let _: E = E::Unit();
66+
//~^ ERROR expected function, found enum variant `E::Unit`
67+
let _: Z = m::n::Z;
68+
//~^ ERROR cannot find type `Z` in this scope
69+
//~| ERROR expected value, found enum `m::n::Z`
70+
//~| ERROR enum `Z` is private
71+
let _: Z = m::n::Z::Fn;
72+
//~^ ERROR cannot find type `Z` in this scope
73+
//~| ERROR enum `Z` is private
74+
let _: Z = m::n::Z::Struct;
75+
//~^ ERROR cannot find type `Z` in this scope
76+
//~| ERROR expected value, found struct variant `m::n::Z::Struct`
77+
//~| ERROR enum `Z` is private
78+
let _: Z = m::n::Z::Unit {};
79+
//~^ ERROR cannot find type `Z` in this scope
80+
//~| ERROR enum `Z` is private
81+
}

0 commit comments

Comments
 (0)