Skip to content

Tweaks to invalid ctor messages #47116

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

Merged
merged 8 commits into from
Jan 21, 2018
Merged
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
48 changes: 30 additions & 18 deletions src/librustc_resolve/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -898,7 +898,7 @@ impl<'a> LexicalScopeBinding<'a> {
}
}

#[derive(Clone)]
#[derive(Clone, Debug)]
enum PathResult<'a> {
Module(Module<'a>),
NonModule(PathResolution),
Expand Down Expand Up @@ -2568,7 +2568,8 @@ impl<'a> Resolver<'a> {
let code = source.error_code(def.is_some());
let (base_msg, fallback_label, base_span) = if let Some(def) = def {
(format!("expected {}, found {} `{}`", expected, def.kind_name(), path_str),
format!("not a {}", expected), span)
format!("not a {}", expected),
span)
} else {
let item_str = path[path.len() - 1].node;
let item_span = path[path.len() - 1].span;
Expand All @@ -2585,7 +2586,8 @@ impl<'a> Resolver<'a> {
(mod_prefix, format!("`{}`", names_to_string(mod_path)))
};
(format!("cannot find {} `{}` in {}{}", expected, item_str, mod_prefix, mod_str),
format!("not found in {}", mod_str), item_span)
format!("not found in {}", mod_str),
item_span)
};
let code = DiagnosticId::Error(code.into());
let mut err = this.session.struct_span_err_with_code(base_span, &base_msg, code);
Expand Down Expand Up @@ -2700,20 +2702,37 @@ impl<'a> Resolver<'a> {
}
return (err, candidates);
},
_ if ns == ValueNS && is_struct_like(def) => {
if let Def::Struct(def_id) = def {
if let Some((ctor_def, ctor_vis))
= this.struct_constructors.get(&def_id).cloned() {
if is_expected(ctor_def) && !this.is_accessible(ctor_vis) {
err.span_label(span, format!("constructor is not visible \
here due to private fields"));
}
(Def::Struct(def_id), _) if ns == ValueNS => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Def::Union(..), Def::Variant(..) and Def::VariantCtor(_, CtorKind::Fictive) can be added here to restore what the previous code did (they are equivalent to structs without accessible constructors in this context).

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Only CtorKind::Fictive is relevant here because for others #47116 (comment) still holds.

if let Some((ctor_def, ctor_vis))
= this.struct_constructors.get(&def_id).cloned() {
let accessible_ctor = this.is_accessible(ctor_vis);
if is_expected(ctor_def) && !accessible_ctor {
err.span_label(span, format!("constructor is not visible \
here due to private fields"));
}
} else {
err.span_label(span, format!("did you mean `{} {{ /* fields */ }}`?",
path_str));
}
return (err, candidates);
}
(Def::Union(..), _) |
(Def::Variant(..), _) |
(Def::VariantCtor(_, CtorKind::Fictive), _) if ns == ValueNS => {
err.span_label(span, format!("did you mean `{} {{ /* fields */ }}`?",
path_str));
return (err, candidates);
}
(Def::SelfTy(..), _) if ns == ValueNS => {
err.span_label(span, fallback_label);
err.note("can't use `Self` as a constructor, you must use the \
implemented struct");
return (err, candidates);
}
(Def::TyAlias(_), _) | (Def::AssociatedTy(..), _) if ns == ValueNS => {
err.note("can't use a type alias as a constructor");
return (err, candidates);
}
_ => {}
}
}
Expand Down Expand Up @@ -3965,13 +3984,6 @@ impl<'a> Resolver<'a> {
}
}

fn is_struct_like(def: Def) -> bool {
match def {
Def::VariantCtor(_, CtorKind::Fictive) => true,
_ => PathSource::Struct.is_expected(def),
}
}

fn is_self_type(path: &[SpannedIdent], namespace: Namespace) -> bool {
namespace == TypeNS && path.len() == 1 && path[0].node.name == keywords::SelfType.name()
}
Expand Down
34 changes: 24 additions & 10 deletions src/librustc_typeck/check/callee.rs
Original file line number Diff line number Diff line change
Expand Up @@ -210,15 +210,25 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
}
}
}
let mut err = type_error_struct!(self.tcx.sess, call_expr.span, callee_ty, E0618,
"expected function, found `{}`",
if let Some(ref path) = unit_variant {
path.to_string()
} else {
callee_ty.to_string()
});
if let Some(path) = unit_variant {
err.help(&format!("did you mean to write `{}`?", path));

let mut err = type_error_struct!(
self.tcx.sess,
call_expr.span,
callee_ty,
E0618,
"expected function, found {}",
match unit_variant {
Some(ref path) => format!("enum variant `{}`", path),
None => format!("`{}`", callee_ty),
});

err.span_label(call_expr.span, "not a function");

if let Some(ref path) = unit_variant {
err.span_suggestion(call_expr.span,
&format!("`{}` is a unit variant, you need to write it \
without the parenthesis", path),
path.to_string());
}

if let hir::ExprCall(ref expr, _) = call_expr.node {
Expand All @@ -235,7 +245,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
_ => self.tcx.hir.span_if_local(def.def_id())
};
if let Some(span) = def_span {
err.span_note(span, "defined here");
let name = match unit_variant {
Some(path) => path,
None => callee_ty.to_string(),
};
err.span_label(span, format!("`{}` defined here", name));
}
}

Expand Down
8 changes: 5 additions & 3 deletions src/librustc_typeck/check/compare_method.rs
Original file line number Diff line number Diff line change
Expand Up @@ -518,7 +518,10 @@ fn compare_self_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
self_descr);
err.span_label(impl_m_span, format!("`{}` used in impl", self_descr));
if let Some(span) = tcx.hir.span_if_local(trait_m.def_id) {
err.span_label(span, format!("trait declared without `{}`", self_descr));
err.span_label(span, format!("trait method declared without `{}`", self_descr));
} else {
err.note_trait_signature(trait_m.name.to_string(),
trait_m.signature(&tcx));
}
err.emit();
return Err(ErrorReported);
Expand All @@ -533,8 +536,7 @@ fn compare_self_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
not in the impl",
trait_m.name,
self_descr);
err.span_label(impl_m_span,
format!("expected `{}` in impl", self_descr));
err.span_label(impl_m_span, format!("expected `{}` in impl", self_descr));
if let Some(span) = tcx.hir.span_if_local(trait_m.def_id) {
err.span_label(span, format!("`{}` used in trait", self_descr));
} else {
Expand Down
8 changes: 5 additions & 3 deletions src/test/compile-fail/E0185.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,16 @@
// except according to those terms.

trait Foo {
fn foo(); //~ trait declared without `&self`
fn foo();
//~^ NOTE trait method declared without `&self`
}

struct Bar;

impl Foo for Bar {
fn foo(&self) {} //~ ERROR E0185
//~^ `&self` used in impl
fn foo(&self) {}
//~^ ERROR E0185
//~| NOTE `&self` used in impl
}

fn main() {
Expand Down
6 changes: 4 additions & 2 deletions src/test/compile-fail/E0618.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,9 @@ enum X {
}

fn main() {
X::Entry(); //~ ERROR expected function, found `X::Entry` [E0618]
X::Entry();
//~^ ERROR expected function, found enum variant `X::Entry` [E0618]
let x = 0i32;
x(); //~ ERROR expected function, found `i32` [E0618]
x();
//~^ ERROR expected function, found `i32` [E0618]
}
2 changes: 1 addition & 1 deletion src/test/ui/block-result/issue-20862.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ error[E0618]: expected function, found `()`
--> $DIR/issue-20862.rs:17:13
|
17 | let x = foo(5)(2);
| ^^^^^^^^^
| ^^^^^^^^^ not a function

error: aborting due to 2 previous errors

4 changes: 2 additions & 2 deletions src/test/ui/empty-struct-unit-expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@ enum E {
fn main() {
let e2 = Empty2(); //~ ERROR expected function, found `Empty2`
let e4 = E::Empty4();
//~^ ERROR expected function, found `E::Empty4` [E0618]
//~^ ERROR expected function, found enum variant `E::Empty4` [E0618]
let xe2 = XEmpty2(); //~ ERROR expected function, found `empty_struct::XEmpty2`
let xe4 = XE::XEmpty4();
//~^ ERROR expected function, found `XE::XEmpty4` [E0618]
//~^ ERROR expected function, found enum variant `XE::XEmpty4` [E0618]
}
37 changes: 18 additions & 19 deletions src/test/ui/empty-struct-unit-expr.stderr
Original file line number Diff line number Diff line change
@@ -1,41 +1,40 @@
error[E0618]: expected function, found `Empty2`
--> $DIR/empty-struct-unit-expr.rs:25:14
|
25 | let e2 = Empty2(); //~ ERROR expected function, found `Empty2`
| ^^^^^^^^
|
note: defined here
--> $DIR/empty-struct-unit-expr.rs:18:1
|
18 | struct Empty2;
| ^^^^^^^^^^^^^^
| -------------- `Empty2` defined here
...
25 | let e2 = Empty2(); //~ ERROR expected function, found `Empty2`
| ^^^^^^^^ not a function

error[E0618]: expected function, found `E::Empty4`
error[E0618]: expected function, found enum variant `E::Empty4`
--> $DIR/empty-struct-unit-expr.rs:26:14
|
21 | Empty4
| ------ `E::Empty4` defined here
...
26 | let e4 = E::Empty4();
| ^^^^^^^^^^^
|
= help: did you mean to write `E::Empty4`?
note: defined here
--> $DIR/empty-struct-unit-expr.rs:21:5
| ^^^^^^^^^^^ not a function
help: `E::Empty4` is a unit variant, you need to write it without the parenthesis
|
21 | Empty4
| ^^^^^^
26 | let e4 = E::Empty4;
| ^^^^^^^^^

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

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

error: aborting due to 4 previous errors

20 changes: 6 additions & 14 deletions src/test/ui/issue-10969.stderr
Original file line number Diff line number Diff line change
@@ -1,26 +1,18 @@
error[E0618]: expected function, found `i32`
--> $DIR/issue-10969.rs:12:5
|
12 | i(); //~ERROR expected function, found `i32`
| ^^^
|
note: defined here
--> $DIR/issue-10969.rs:11:9
|
11 | fn func(i: i32) {
| ^
| - `i32` defined here
12 | i(); //~ERROR expected function, found `i32`
| ^^^ not a function

error[E0618]: expected function, found `i32`
--> $DIR/issue-10969.rs:16:5
|
16 | i(); //~ERROR expected function, found `i32`
| ^^^
|
note: defined here
--> $DIR/issue-10969.rs:15:9
|
15 | let i = 0i32;
| ^
| - `i32` defined here
16 | i(); //~ERROR expected function, found `i32`
| ^^^ not a function

error: aborting due to 2 previous errors

81 changes: 81 additions & 0 deletions src/test/ui/resolve/privacy-enum-ctor.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
// Copyright 2016 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.

mod m {
pub enum E {
Fn(u8),
Struct {
s: u8,
},
Unit,
}

pub mod n {
pub(in m) enum Z {
Fn(u8),
Struct {
s: u8,
},
Unit,
}
}

use m::n::Z; // OK, only the type is imported

fn f() {
n::Z;
//~^ ERROR expected value, found enum `n::Z`
Z;
//~^ ERROR expected value, found enum `Z`
let _: Z = Z::Fn;
//~^ ERROR mismatched types
let _: Z = Z::Struct;
//~^ ERROR expected value, found struct variant `Z::Struct`
let _ = Z::Unit();
//~^ ERROR expected function, found enum variant `Z::Unit`
let _ = Z::Unit {};
// This is ok, it is equivalent to not having braces
}
}

use m::E; // OK, only the type is imported

fn main() {
let _: E = m::E;
//~^ ERROR expected value, found enum `m::E`
let _: E = m::E::Fn;
//~^ ERROR mismatched types
let _: E = m::E::Struct;
//~^ ERROR expected value, found struct variant `m::E::Struct`
let _: E = m::E::Unit();
//~^ ERROR expected function, found enum variant `m::E::Unit`
let _: E = E;
//~^ ERROR expected value, found enum `E`
let _: E = E::Fn;
//~^ ERROR mismatched types
let _: E = E::Struct;
//~^ ERROR expected value, found struct variant `E::Struct`
let _: E = E::Unit();
//~^ ERROR expected function, found enum variant `E::Unit`
let _: Z = m::n::Z;
//~^ ERROR cannot find type `Z` in this scope
//~| ERROR expected value, found enum `m::n::Z`
//~| ERROR enum `Z` is private
let _: Z = m::n::Z::Fn;
//~^ ERROR cannot find type `Z` in this scope
//~| ERROR enum `Z` is private
let _: Z = m::n::Z::Struct;
//~^ ERROR cannot find type `Z` in this scope
//~| ERROR expected value, found struct variant `m::n::Z::Struct`
//~| ERROR enum `Z` is private
let _: Z = m::n::Z::Unit {};
//~^ ERROR cannot find type `Z` in this scope
//~| ERROR enum `Z` is private
}
Loading