]> git.lizzy.rs Git - rust.git/blobdiff - src/librustc_trait_selection/traits/error_reporting/mod.rs
On recursive ADT, provide indirection structured suggestion
[rust.git] / src / librustc_trait_selection / traits / error_reporting / mod.rs
index 41811bf44b1aff3f48553d983414bfb866b0930d..3457f7b4580c5ec8360a0cadd76221b36212c4b7 100644 (file)
@@ -290,7 +290,7 @@ fn report_selection_error(
                             (
                                 Some(format!(
                                     "`?` couldn't convert the error to `{}`",
-                                    trait_ref.self_ty(),
+                                    trait_ref.skip_binder().self_ty(),
                                 )),
                                 Some(
                                     "the question mark operation (`?`) implicitly performs a \
@@ -340,7 +340,10 @@ fn report_selection_error(
                             if let Some(ret_span) = self.return_type_span(obligation) {
                                 err.span_label(
                                     ret_span,
-                                    &format!("expected `{}` because of this", trait_ref.self_ty()),
+                                    &format!(
+                                        "expected `{}` because of this",
+                                        trait_ref.skip_binder().self_ty()
+                                    ),
                                 );
                             }
                         }
@@ -353,7 +356,7 @@ fn report_selection_error(
                                     "{}the trait `{}` is not implemented for `{}`",
                                     pre_message,
                                     trait_ref.print_only_trait_path(),
-                                    trait_ref.self_ty(),
+                                    trait_ref.skip_binder().self_ty(),
                                 )
                             };
 
@@ -643,7 +646,10 @@ fn report_selection_error(
                     return;
                 }
 
-                let found_trait_ty = found_trait_ref.self_ty();
+                let found_trait_ty = match found_trait_ref.self_ty().no_bound_vars() {
+                    Some(ty) => ty,
+                    None => return,
+                };
 
                 let found_did = match found_trait_ty.kind {
                     ty::Closure(did, _) | ty::Foreign(did) | ty::FnDef(did, _) => Some(did),
@@ -1360,11 +1366,15 @@ fn note_version_mismatch(
     ) {
         let get_trait_impl = |trait_def_id| {
             let mut trait_impl = None;
-            self.tcx.for_each_relevant_impl(trait_def_id, trait_ref.self_ty(), |impl_def_id| {
-                if trait_impl.is_none() {
-                    trait_impl = Some(impl_def_id);
-                }
-            });
+            self.tcx.for_each_relevant_impl(
+                trait_def_id,
+                trait_ref.skip_binder().self_ty(),
+                |impl_def_id| {
+                    if trait_impl.is_none() {
+                        trait_impl = Some(impl_def_id);
+                    }
+                },
+            );
             trait_impl
         };
         let required_trait_path = self.tcx.def_path_str(trait_ref.def_id());
@@ -1435,7 +1445,7 @@ fn maybe_report_ambiguity(
         let mut err = match predicate.kind() {
             ty::PredicateKind::Trait(ref data, _) => {
                 let trait_ref = data.to_poly_trait_ref();
-                let self_ty = trait_ref.self_ty();
+                let self_ty = trait_ref.skip_binder().self_ty();
                 debug!("self_ty {:?} {:?} trait_ref {:?}", self_ty, self_ty.kind, trait_ref);
 
                 if predicate.references_error() {
@@ -1564,7 +1574,7 @@ fn maybe_report_ambiguity(
             }
             ty::PredicateKind::Projection(ref data) => {
                 let trait_ref = data.to_poly_trait_ref(self.tcx);
-                let self_ty = trait_ref.self_ty();
+                let self_ty = trait_ref.skip_binder().self_ty();
                 let ty = data.skip_binder().ty;
                 if predicate.references_error() {
                     return;
@@ -1737,24 +1747,62 @@ fn is_recursive_obligation(
 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 short_msg = format!("insert some indirection to make `{}` representable", path);
+    let msg = format!(
+        "insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `{}` representable",
+        path,
+    );
+    match &spans[..] {
+        [span] => {
+            err.multipart_suggestions(
+                &short_msg,
+                vec![
+                    vec![
+                        (span.shrink_to_lo(), "Box<".to_string()),
+                        (span.shrink_to_hi(), ">".to_string()),
+                    ],
+                    vec![
+                        (span.shrink_to_lo(), "Rc<".to_string()),
+                        (span.shrink_to_hi(), ">".to_string()),
+                    ],
+                    vec![(span.shrink_to_lo(), "&".to_string())],
+                ],
+                Applicability::HasPlaceholders,
+            );
+        }
+        _ 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,
+            );
+        }
+        _ => {
+            err.help(&msg);
+        }
+    }
+    err.emit();
 }
 
 /// Summarizes information