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

On recursive ADT, provide indirection structured suggestion #72740

Merged
merged 3 commits into from
Jun 15, 2020
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
23 changes: 23 additions & 0 deletions src/librustc_errors/diagnostic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -296,6 +296,29 @@ impl Diagnostic {
self
}

pub fn multipart_suggestions(
&mut self,
msg: &str,
suggestions: Vec<Vec<(Span, String)>>,
applicability: Applicability,
) -> &mut Self {
self.suggestions.push(CodeSuggestion {
substitutions: suggestions
.into_iter()
.map(|suggestion| Substitution {
parts: suggestion
.into_iter()
.map(|(span, snippet)| SubstitutionPart { snippet, span })
.collect(),
})
.collect(),
msg: msg.to_owned(),
style: SuggestionStyle::ShowCode,
applicability,
});
self
}

/// Prints out a message with for a multipart suggestion without showing the suggested code.
///
/// This is intended to be used for suggestions that are obvious in what the changes need to
Expand Down
13 changes: 13 additions & 0 deletions src/librustc_errors/diagnostic_builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,19 @@ impl<'a> DiagnosticBuilder<'a> {
self
}

pub fn multipart_suggestions(
&mut self,
msg: &str,
suggestions: Vec<Vec<(Span, String)>>,
applicability: Applicability,
) -> &mut Self {
if !self.0.allow_suggestions {
return self;
}
self.0.diagnostic.multipart_suggestions(msg, suggestions, applicability);
self
}

pub fn tool_only_multipart_suggestion(
&mut self,
msg: &str,
Expand Down
10 changes: 9 additions & 1 deletion src/librustc_middle/ty/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -827,7 +827,15 @@ impl<'tcx> ty::TyS<'tcx> {
// Find non representable fields with their spans
fold_repr(def.all_fields().map(|field| {
let ty = field.ty(tcx, substs);
let span = tcx.hir().span_if_local(field.did).unwrap_or(sp);
let span = match field
.did
.as_local()
.map(|id| tcx.hir().as_local_hir_id(id))
.and_then(|id| tcx.hir().find(id))
{
Some(hir::Node::Field(field)) => field.ty.span,
_ => sp,
};
match is_type_structurally_recursive(
tcx,
span,
Expand Down
45 changes: 31 additions & 14 deletions src/librustc_trait_selection/traits/error_reporting/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1747,24 +1747,41 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> {
pub fn recursive_type_with_infinite_size_error(
tcx: TyCtxt<'tcx>,
type_def_id: DefId,
) -> DiagnosticBuilder<'tcx> {
spans: Vec<Span>,
) {
assert!(type_def_id.is_local());
let span = tcx.hir().span_if_local(type_def_id).unwrap();
let span = tcx.sess.source_map().guess_head_span(span);
let mut err = struct_span_err!(
tcx.sess,
span,
E0072,
"recursive type `{}` has infinite size",
tcx.def_path_str(type_def_id)
);
let path = tcx.def_path_str(type_def_id);
let mut err =
struct_span_err!(tcx.sess, span, E0072, "recursive type `{}` has infinite size", path);
err.span_label(span, "recursive type has infinite size");
err.help(&format!(
"insert indirection (e.g., a `Box`, `Rc`, or `&`) \
at some point to make `{}` representable",
tcx.def_path_str(type_def_id)
));
err
for &span in &spans {
err.span_label(span, "recursive without indirection");
}
let msg = format!(
"insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `{}` representable",
path,
);
if spans.len() <= 4 {
err.multipart_suggestion(
&msg,
spans
.iter()
.flat_map(|&span| {
vec![
(span.shrink_to_lo(), "Box<".to_string()),
(span.shrink_to_hi(), ">".to_string()),
]
.into_iter()
})
.collect(),
Applicability::HasPlaceholders,
);
} else {
err.help(&msg);
}
err.emit();
}

/// Summarizes information
Expand Down
6 changes: 1 addition & 5 deletions src/librustc_typeck/check/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2390,11 +2390,7 @@ fn check_representable(tcx: TyCtxt<'_>, sp: Span, item_def_id: LocalDefId) -> bo
// caught by case 1.
match rty.is_representable(tcx, sp) {
Representability::SelfRecursive(spans) => {
let mut err = recursive_type_with_infinite_size_error(tcx, item_def_id.to_def_id());
for span in spans {
err.span_label(span, "recursive without indirection");
}
err.emit();
recursive_type_with_infinite_size_error(tcx, item_def_id.to_def_id(), spans);
return false;
}
Representability::Representable | Representability::ContainsRecursive => (),
Expand Down
5 changes: 4 additions & 1 deletion src/test/ui/infinite/infinite-tag-type-recursion.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,10 @@ LL | enum MList { Cons(isize, MList), Nil }
| |
| recursive type has infinite size
|
= help: insert indirection (e.g., a `Box`, `Rc`, or `&`) at some point to make `MList` representable
help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `MList` representable
|
LL | enum MList { Cons(isize, Box<MList>), Nil }
| ^^^^ ^

error[E0391]: cycle detected when computing drop-check constraints for `MList`
--> $DIR/infinite-tag-type-recursion.rs:1:1
Expand Down
7 changes: 5 additions & 2 deletions src/test/ui/issues/issue-17431-1.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,14 @@ error[E0072]: recursive type `Foo` has infinite size
--> $DIR/issue-17431-1.rs:1:1
|
LL | struct Foo { foo: Option<Option<Foo>> }
| ^^^^^^^^^^ ------------------------ recursive without indirection
| ^^^^^^^^^^ ------------------- recursive without indirection
| |
| recursive type has infinite size
|
= help: insert indirection (e.g., a `Box`, `Rc`, or `&`) at some point to make `Foo` representable
help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `Foo` representable
|
LL | struct Foo { foo: Box<Option<Option<Foo>>> }
| ^^^^ ^

error: aborting due to previous error

Expand Down
14 changes: 10 additions & 4 deletions src/test/ui/issues/issue-17431-2.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,27 @@ error[E0072]: recursive type `Baz` has infinite size
--> $DIR/issue-17431-2.rs:1:1
|
LL | struct Baz { q: Option<Foo> }
| ^^^^^^^^^^ -------------- recursive without indirection
| ^^^^^^^^^^ ----------- recursive without indirection
| |
| recursive type has infinite size
|
= help: insert indirection (e.g., a `Box`, `Rc`, or `&`) at some point to make `Baz` representable
help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `Baz` representable
|
LL | struct Baz { q: Box<Option<Foo>> }
| ^^^^ ^

error[E0072]: recursive type `Foo` has infinite size
--> $DIR/issue-17431-2.rs:4:1
|
LL | struct Foo { q: Option<Baz> }
| ^^^^^^^^^^ -------------- recursive without indirection
| ^^^^^^^^^^ ----------- recursive without indirection
| |
| recursive type has infinite size
|
= help: insert indirection (e.g., a `Box`, `Rc`, or `&`) at some point to make `Foo` representable
help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `Foo` representable
|
LL | struct Foo { q: Box<Option<Baz>> }
| ^^^^ ^

error: aborting due to 2 previous errors

Expand Down
7 changes: 5 additions & 2 deletions src/test/ui/issues/issue-17431-3.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,14 @@ error[E0072]: recursive type `Foo` has infinite size
--> $DIR/issue-17431-3.rs:3:1
|
LL | struct Foo { foo: Mutex<Option<Foo>> }
| ^^^^^^^^^^ ----------------------- recursive without indirection
| ^^^^^^^^^^ ------------------ recursive without indirection
| |
| recursive type has infinite size
|
= help: insert indirection (e.g., a `Box`, `Rc`, or `&`) at some point to make `Foo` representable
help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `Foo` representable
|
LL | struct Foo { foo: Box<Mutex<Option<Foo>>> }
| ^^^^ ^

error: aborting due to previous error

Expand Down
7 changes: 5 additions & 2 deletions src/test/ui/issues/issue-17431-4.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,14 @@ error[E0072]: recursive type `Foo` has infinite size
--> $DIR/issue-17431-4.rs:3:1
|
LL | struct Foo<T> { foo: Option<Option<Foo<T>>>, marker: marker::PhantomData<T> }
| ^^^^^^^^^^^^^ --------------------------- recursive without indirection
| ^^^^^^^^^^^^^ ---------------------- recursive without indirection
| |
| recursive type has infinite size
|
= help: insert indirection (e.g., a `Box`, `Rc`, or `&`) at some point to make `Foo` representable
help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `Foo` representable
|
LL | struct Foo<T> { foo: Box<Option<Option<Foo<T>>>>, marker: marker::PhantomData<T> }
| ^^^^ ^

error: aborting due to previous error

Expand Down
7 changes: 5 additions & 2 deletions src/test/ui/issues/issue-17431-5.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,14 @@ error[E0072]: recursive type `Bar` has infinite size
--> $DIR/issue-17431-5.rs:5:1
|
LL | struct Bar<T> { x: Bar<Foo> , marker: marker::PhantomData<T> }
| ^^^^^^^^^^^^^ ----------- recursive without indirection
| ^^^^^^^^^^^^^ -------- recursive without indirection
| |
| recursive type has infinite size
|
= help: insert indirection (e.g., a `Box`, `Rc`, or `&`) at some point to make `Bar` representable
help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `Bar` representable
|
LL | struct Bar<T> { x: Box<Bar<Foo>> , marker: marker::PhantomData<T> }
| ^^^^ ^

error: aborting due to previous error

Expand Down
5 changes: 4 additions & 1 deletion src/test/ui/issues/issue-17431-6.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,10 @@ LL | enum Foo { X(Mutex<Option<Foo>>) }
| |
| recursive type has infinite size
|
= help: insert indirection (e.g., a `Box`, `Rc`, or `&`) at some point to make `Foo` representable
help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `Foo` representable
|
LL | enum Foo { X(Box<Mutex<Option<Foo>>>) }
| ^^^^ ^

error: aborting due to previous error

Expand Down
5 changes: 4 additions & 1 deletion src/test/ui/issues/issue-17431-7.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,10 @@ LL | enum Foo { Voo(Option<Option<Foo>>) }
| |
| recursive type has infinite size
|
= help: insert indirection (e.g., a `Box`, `Rc`, or `&`) at some point to make `Foo` representable
help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `Foo` representable
|
LL | enum Foo { Voo(Box<Option<Option<Foo>>>) }
| ^^^^ ^

error: aborting due to previous error

Expand Down
5 changes: 4 additions & 1 deletion src/test/ui/issues/issue-2718-a.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,10 @@ LL | pub struct Pong(SendPacket<Ping>);
| | recursive without indirection
| recursive type has infinite size
|
= help: insert indirection (e.g., a `Box`, `Rc`, or `&`) at some point to make `pingpong::Pong` representable
help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `pingpong::Pong` representable
|
LL | pub struct Pong(Box<SendPacket<Ping>>);
| ^^^^ ^

error: aborting due to previous error

Expand Down
5 changes: 4 additions & 1 deletion src/test/ui/issues/issue-3008-1.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,10 @@ LL | enum Bar {
LL | BarSome(Bar)
| --- recursive without indirection
|
= help: insert indirection (e.g., a `Box`, `Rc`, or `&`) at some point to make `Bar` representable
help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `Bar` representable
|
LL | BarSome(Box<Bar>)
| ^^^^ ^

error: aborting due to previous error

Expand Down
7 changes: 5 additions & 2 deletions src/test/ui/issues/issue-3008-2.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,14 @@ error[E0072]: recursive type `Bar` has infinite size
--> $DIR/issue-3008-2.rs:2:1
|
LL | struct Bar { x: Bar }
| ^^^^^^^^^^ ------ recursive without indirection
| ^^^^^^^^^^ --- recursive without indirection
| |
| recursive type has infinite size
|
= help: insert indirection (e.g., a `Box`, `Rc`, or `&`) at some point to make `Bar` representable
help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `Bar` representable
|
LL | struct Bar { x: Box<Bar> }
| ^^^^ ^

error: aborting due to previous error

Expand Down
5 changes: 4 additions & 1 deletion src/test/ui/issues/issue-3008-3.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,10 @@ LL | enum E2<T> { V2(E2<E1>, marker::PhantomData<T>), }
| |
| recursive type has infinite size
|
= help: insert indirection (e.g., a `Box`, `Rc`, or `&`) at some point to make `E2` representable
help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `E2` representable
|
LL | enum E2<T> { V2(Box<E2<E1>>, marker::PhantomData<T>), }
| ^^^^ ^

error: aborting due to previous error

Expand Down
5 changes: 4 additions & 1 deletion src/test/ui/issues/issue-32326.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,10 @@ LL | Plus(Expr, Expr),
| |
| recursive without indirection
|
= help: insert indirection (e.g., a `Box`, `Rc`, or `&`) at some point to make `Expr` representable
help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `Expr` representable
|
LL | Plus(Box<Expr>, Box<Expr>),
| ^^^^ ^ ^^^^ ^

error: aborting due to previous error

Expand Down
7 changes: 5 additions & 2 deletions src/test/ui/issues/issue-3779.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,12 @@ LL | struct S {
| ^^^^^^^^ recursive type has infinite size
LL |
LL | element: Option<S>
| ------------------ recursive without indirection
| --------- recursive without indirection
|
= help: insert indirection (e.g., a `Box`, `Rc`, or `&`) at some point to make `S` representable
help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `S` representable
|
LL | element: Box<Option<S>>
| ^^^^ ^

error: aborting due to previous error

Expand Down
10 changes: 8 additions & 2 deletions src/test/ui/issues/issue-57271.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,10 @@ LL | Class(ClassTypeSignature),
LL | Array(TypeSignature),
| ------------- recursive without indirection
|
= help: insert indirection (e.g., a `Box`, `Rc`, or `&`) at some point to make `ObjectType` representable
help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `ObjectType` representable
|
LL | Array(Box<TypeSignature>),
| ^^^^ ^

error[E0072]: recursive type `TypeSignature` has infinite size
--> $DIR/issue-57271.rs:19:1
Expand All @@ -18,7 +21,10 @@ LL | Base(BaseType),
LL | Object(ObjectType),
| ---------- recursive without indirection
|
= help: insert indirection (e.g., a `Box`, `Rc`, or `&`) at some point to make `TypeSignature` representable
help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `TypeSignature` representable
|
LL | Object(Box<ObjectType>),
| ^^^^ ^

error: aborting due to 2 previous errors

Expand Down
5 changes: 4 additions & 1 deletion src/test/ui/issues/issue-72554.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,10 @@ LL | pub enum ElemDerived {
LL | A(ElemDerived)
| ----------- recursive without indirection
|
= help: insert indirection (e.g., a `Box`, `Rc`, or `&`) at some point to make `ElemDerived` representable
help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `ElemDerived` representable
|
LL | A(Box<ElemDerived>)
| ^^^^ ^

error: aborting due to previous error

Expand Down
5 changes: 4 additions & 1 deletion src/test/ui/recursion/recursive-enum.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,10 @@ LL | enum List<T> { Cons(T, List<T>), Nil }
| |
| recursive type has infinite size
|
= help: insert indirection (e.g., a `Box`, `Rc`, or `&`) at some point to make `List` representable
help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `List` representable
|
LL | enum List<T> { Cons(T, Box<List<T>>), Nil }
| ^^^^ ^

error: aborting due to previous error

Expand Down
Loading