Skip to content

Commit

Permalink
Rollup merge of #78401 - davidtwco:issue-75906-tuple-construct-privat…
Browse files Browse the repository at this point in the history
…e-field, r=estebank

resolve: private fields in tuple struct ctor diag

Fixes #75906.

This PR improves the diagnostic emitted when a tuple struct is being constructed which has private fields so that private fields are labelled and the message is improved.

r? @estebank
  • Loading branch information
Dylan-DPC authored Oct 28, 2020
2 parents c3f842b + 27bb27f commit c9279c8
Show file tree
Hide file tree
Showing 13 changed files with 108 additions and 57 deletions.
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(
"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() => {
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()));
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

0 comments on commit c9279c8

Please sign in to comment.