Skip to content
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

resolve: private fields in tuple struct ctor diag #78401

Merged
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
105 changes: 61 additions & 44 deletions compiler/rustc_resolve/src/late/diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -917,54 +917,71 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
self.suggest_using_enum_variant(err, source, def_id, span);
}
(Res::Def(DefKind::Struct, def_id), _) if ns == ValueNS => {
if let Some((ctor_def, ctor_vis, fields)) =
self.r.struct_constructors.get(&def_id).cloned()
let (ctor_def, ctor_vis, fields) =
if let Some(struct_ctor) = self.r.struct_constructors.get(&def_id).cloned() {
struct_ctor
} else {
bad_struct_syntax_suggestion(def_id);
return true;
};

let is_accessible = self.r.is_accessible_from(ctor_vis, self.parent_scope.module);
if !is_expected(ctor_def) || is_accessible {
return true;
}

let field_spans = match source {
// e.g. `if let Enum::TupleVariant(field1, field2) = _`
PathSource::TupleStruct(_, pattern_spans) => {
err.set_primary_message(
davidtwco marked this conversation as resolved.
Show resolved Hide resolved
"cannot match against a tuple struct which contains private fields",
);

// Use spans of the tuple struct pattern.
Some(Vec::from(pattern_spans))
}
// e.g. `let _ = Enum::TupleVariant(field1, field2);`
_ if source.is_call() => {
davidtwco marked this conversation as resolved.
Show resolved Hide resolved
err.set_primary_message(
"cannot initialize a tuple struct which contains private fields",
);

// Use spans of the tuple struct definition.
self.r
.field_names
.get(&def_id)
.map(|fields| fields.iter().map(|f| f.span).collect::<Vec<_>>())
}
_ => None,
};

if let Some(spans) =
field_spans.filter(|spans| spans.len() > 0 && fields.len() == spans.len())
{
let accessible_ctor =
self.r.is_accessible_from(ctor_vis, self.parent_scope.module);
if is_expected(ctor_def) && !accessible_ctor {
let mut better_diag = false;
if let PathSource::TupleStruct(_, pattern_spans) = source {
if pattern_spans.len() > 0 && fields.len() == pattern_spans.len() {
let non_visible_spans: Vec<Span> = fields
.iter()
.zip(pattern_spans.iter())
.filter_map(|(vis, span)| {
match self
.r
.is_accessible_from(*vis, self.parent_scope.module)
{
true => None,
false => Some(*span),
}
})
.collect();
// Extra check to be sure
if non_visible_spans.len() > 0 {
let mut m: rustc_span::MultiSpan =
non_visible_spans.clone().into();
non_visible_spans.into_iter().for_each(|s| {
m.push_span_label(s, "private field".to_string())
});
err.span_note(
m,
"constructor is not visible here due to private fields",
);
better_diag = true;
}
}
}
let non_visible_spans: Vec<Span> = fields
.iter()
.zip(spans.iter())
.filter(|(vis, _)| {
!self.r.is_accessible_from(**vis, self.parent_scope.module)
})
.map(|(_, span)| *span)
.collect();

if !better_diag {
err.span_label(
span,
"constructor is not visible here due to private fields".to_string(),
);
}
if non_visible_spans.len() > 0 {
let mut m: rustc_span::MultiSpan = non_visible_spans.clone().into();
non_visible_spans
.into_iter()
.for_each(|s| m.push_span_label(s, "private field".to_string()));
Comment on lines +972 to +974
Copy link
Contributor

Choose a reason for hiding this comment

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

oh! I hadn't thought about doing this this way! neat.

err.span_note(m, "constructor is not visible here due to private fields");
}
} else {
bad_struct_syntax_suggestion(def_id);

return true;
}

err.span_label(
span,
"constructor is not visible here due to private fields".to_string(),
);
}
(
Res::Def(
Expand Down
2 changes: 1 addition & 1 deletion src/test/ui/issues/issue-38412.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
fn main() {
let Box(a) = loop { };
//~^ ERROR expected tuple struct or tuple variant, found struct `Box`
//~^ ERROR cannot match against a tuple struct which contains private fields

// (The below is a trick to allow compiler to infer a type for
// variable `a` without attempting to ascribe a type to the
Expand Down
2 changes: 1 addition & 1 deletion src/test/ui/issues/issue-38412.stderr
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
error[E0532]: expected tuple struct or tuple variant, found struct `Box`
error[E0532]: cannot match against a tuple struct which contains private fields
--> $DIR/issue-38412.rs:2:9
|
LL | let Box(a) = loop { };
Expand Down
2 changes: 1 addition & 1 deletion src/test/ui/issues/issue-42944.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ mod bar {

fn foo() {
Bx(());
//~^ ERROR expected function, tuple struct or tuple variant, found struct `Bx` [E0423]
//~^ ERROR cannot initialize a tuple struct which contains private fields [E0423]
}
}

Expand Down
10 changes: 8 additions & 2 deletions src/test/ui/issues/issue-42944.stderr
Original file line number Diff line number Diff line change
@@ -1,8 +1,14 @@
error[E0423]: expected function, tuple struct or tuple variant, found struct `Bx`
error[E0423]: cannot initialize a tuple struct which contains private fields
--> $DIR/issue-42944.rs:9:9
|
LL | Bx(());
| ^^ constructor is not visible here due to private fields
| ^^
|
note: constructor is not visible here due to private fields
--> $DIR/issue-42944.rs:2:19
|
LL | pub struct Bx(());
| ^^ private field

error[E0425]: cannot find function, tuple struct or tuple variant `Bx` in this scope
--> $DIR/issue-42944.rs:16:9
Expand Down
13 changes: 13 additions & 0 deletions src/test/ui/issues/issue-75906.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
mod m {
pub struct Foo { x: u8 }

pub struct Bar(u8);
}

use m::{Foo, Bar};

fn main() {
let x = Foo { x: 12 };
let y = Bar(12);
//~^ ERROR cannot initialize a tuple struct which contains private fields [E0423]
}
15 changes: 15 additions & 0 deletions src/test/ui/issues/issue-75906.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
error[E0423]: cannot initialize a tuple struct which contains private fields
--> $DIR/issue-75906.rs:11:13
|
LL | let y = Bar(12);
| ^^^
|
note: constructor is not visible here due to private fields
--> $DIR/issue-75906.rs:4:20
|
LL | pub struct Bar(u8);
| ^^ private field

error: aborting due to previous error

For more information about this error, try `rustc --explain E0423`.
4 changes: 2 additions & 2 deletions src/test/ui/issues/issue-75907.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,6 @@ use foo::{make_bar, Bar, Foo};

fn main() {
let Bar(x, y, Foo(z)) = make_bar();
//~^ ERROR expected tuple struct
//~| ERROR expected tuple struct
//~^ ERROR cannot match against a tuple struct which contains private fields
//~| ERROR cannot match against a tuple struct which contains private fields
}
4 changes: 2 additions & 2 deletions src/test/ui/issues/issue-75907.stderr
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
error[E0532]: expected tuple struct or tuple variant, found struct `Bar`
error[E0532]: cannot match against a tuple struct which contains private fields
--> $DIR/issue-75907.rs:15:9
|
LL | let Bar(x, y, Foo(z)) = make_bar();
Expand All @@ -12,7 +12,7 @@ LL | let Bar(x, y, Foo(z)) = make_bar();
| |
| private field

error[E0532]: expected tuple struct or tuple variant, found struct `Foo`
error[E0532]: cannot match against a tuple struct which contains private fields
--> $DIR/issue-75907.rs:15:19
|
LL | let Bar(x, y, Foo(z)) = make_bar();
Expand Down
2 changes: 1 addition & 1 deletion src/test/ui/issues/issue-75907_b.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,5 @@ use a::{make_bar, Bar};

fn main() {
let Bar(x, y, z) = make_bar();
//~^ ERROR expected tuple struct
//~^ ERROR cannot match against a tuple struct which contains private fields
}
2 changes: 1 addition & 1 deletion src/test/ui/issues/issue-75907_b.stderr
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
error[E0532]: expected tuple struct or tuple variant, found struct `Bar`
error[E0532]: cannot match against a tuple struct which contains private fields
--> $DIR/issue-75907_b.rs:9:9
|
LL | let Bar(x, y, z) = make_bar();
Expand Down
2 changes: 1 addition & 1 deletion src/test/ui/rfc-2008-non-exhaustive/struct.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ fn main() {
//~^ ERROR `..` required with struct marked as non-exhaustive

let ts = TupleStruct(640, 480);
//~^ ERROR expected function, tuple struct or tuple variant, found struct `TupleStruct` [E0423]
//~^ ERROR cannot initialize a tuple struct which contains private fields [E0423]

let ts_explicit = structs::TupleStruct(640, 480);
//~^ ERROR tuple struct constructor `TupleStruct` is private [E0603]
Expand Down
2 changes: 1 addition & 1 deletion src/test/ui/rfc-2008-non-exhaustive/struct.stderr
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
error[E0423]: expected function, tuple struct or tuple variant, found struct `TupleStruct`
error[E0423]: cannot initialize a tuple struct which contains private fields
--> $DIR/struct.rs:20:14
|
LL | let ts = TupleStruct(640, 480);
Expand Down