Skip to content

Commit

Permalink
Auto merge of #47116 - estebank:non-accessible-ctor, r=petrochenkov
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
bors committed Jan 21, 2018
2 parents 3001ab1 + 0674050 commit 97520cc
Show file tree
Hide file tree
Showing 14 changed files with 466 additions and 116 deletions.
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 => {
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

0 comments on commit 97520cc

Please sign in to comment.