about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2018-02-13 00:14:11 +0000
committerbors <bors@rust-lang.org>2018-02-13 00:14:11 +0000
commit4d2d3fc5dadf894a8ad709a5860a549f2c0b1032 (patch)
tree083692288e797b23cbc748b69f0ed20a292fabbf /src
parent16362c737fe740f630ada06349fa9004e2a51bb7 (diff)
parent80b8c808baaba629e73440abf52ee4bbfdb5c0f8 (diff)
downloadrust-4d2d3fc5dadf894a8ad709a5860a549f2c0b1032.tar.gz
rust-4d2d3fc5dadf894a8ad709a5860a549f2c0b1032.zip
Auto merge of #47804 - retep007:recursive-requirements, r=pnkfelix
Optimized error reporting for recursive requirements #47720

Fixes #47720
Diffstat (limited to 'src')
-rw-r--r--src/librustc/traits/error_reporting.rs40
-rw-r--r--src/test/ui/recursive-requirements.rs27
-rw-r--r--src/test/ui/recursive-requirements.stderr14
3 files changed, 72 insertions, 9 deletions
diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs
index a290839425e..214d8ec325f 100644
--- a/src/librustc/traits/error_reporting.rs
+++ b/src/librustc/traits/error_reporting.rs
@@ -1224,13 +1224,15 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
     {
         self.note_obligation_cause_code(err,
                                         &obligation.predicate,
-                                        &obligation.cause.code);
+                                        &obligation.cause.code,
+                                        &mut vec![]);
     }
 
     fn note_obligation_cause_code<T>(&self,
                                      err: &mut DiagnosticBuilder,
                                      predicate: &T,
-                                     cause_code: &ObligationCauseCode<'tcx>)
+                                     cause_code: &ObligationCauseCode<'tcx>,
+                                     obligated_types: &mut Vec<&ty::TyS<'tcx>>)
         where T: fmt::Display
     {
         let tcx = self.tcx;
@@ -1326,12 +1328,17 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
             }
             ObligationCauseCode::BuiltinDerivedObligation(ref data) => {
                 let parent_trait_ref = self.resolve_type_vars_if_possible(&data.parent_trait_ref);
-                err.note(&format!("required because it appears within the type `{}`",
-                                  parent_trait_ref.0.self_ty()));
+                let ty = parent_trait_ref.0.self_ty();
+                err.note(&format!("required because it appears within the type `{}`", ty));
+                obligated_types.push(ty);
+
                 let parent_predicate = parent_trait_ref.to_predicate();
-                self.note_obligation_cause_code(err,
-                                                &parent_predicate,
-                                                &data.parent_code);
+                if !self.is_recursive_obligation(obligated_types, &data.parent_code) {
+                    self.note_obligation_cause_code(err,
+                                                    &parent_predicate,
+                                                    &data.parent_code,
+                                                    obligated_types);
+                }
             }
             ObligationCauseCode::ImplDerivedObligation(ref data) => {
                 let parent_trait_ref = self.resolve_type_vars_if_possible(&data.parent_trait_ref);
@@ -1341,8 +1348,9 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
                              parent_trait_ref.0.self_ty()));
                 let parent_predicate = parent_trait_ref.to_predicate();
                 self.note_obligation_cause_code(err,
-                                                &parent_predicate,
-                                                &data.parent_code);
+                                            &parent_predicate,
+                                            &data.parent_code,
+                                            obligated_types);
             }
             ObligationCauseCode::CompareImplMethodObligation { .. } => {
                 err.note(
@@ -1361,6 +1369,20 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
         err.help(&format!("consider adding a `#![recursion_limit=\"{}\"]` attribute to your crate",
                           suggested_limit));
     }
+
+    fn is_recursive_obligation(&self,
+                                   obligated_types: &mut Vec<&ty::TyS<'tcx>>,
+                                   cause_code: &ObligationCauseCode<'tcx>) -> bool {
+        if let ObligationCauseCode::BuiltinDerivedObligation(ref data) = cause_code {
+            let parent_trait_ref = self.resolve_type_vars_if_possible(&data.parent_trait_ref);
+            for obligated_type in obligated_types {
+                if obligated_type == &parent_trait_ref.0.self_ty() {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
 }
 
 enum ArgKind {
diff --git a/src/test/ui/recursive-requirements.rs b/src/test/ui/recursive-requirements.rs
new file mode 100644
index 00000000000..2c0f0338b2d
--- /dev/null
+++ b/src/test/ui/recursive-requirements.rs
@@ -0,0 +1,27 @@
+// Copyright 2018 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.
+
+use std::marker::PhantomData;
+
+struct AssertSync<T: Sync>(PhantomData<T>);
+
+pub struct Foo {
+    bar: *const Bar,
+    phantom: PhantomData<Bar>,
+}
+
+pub struct Bar {
+    foo: *const Foo,
+    phantom: PhantomData<Foo>,
+}
+
+fn main() {
+    let _: AssertSync<Foo> = unimplemented!(); //~ ERROR E0275
+}
diff --git a/src/test/ui/recursive-requirements.stderr b/src/test/ui/recursive-requirements.stderr
new file mode 100644
index 00000000000..8cf2c65b1e2
--- /dev/null
+++ b/src/test/ui/recursive-requirements.stderr
@@ -0,0 +1,14 @@
+error[E0275]: overflow evaluating the requirement `Foo: std::marker::Sync`
+  --> $DIR/recursive-requirements.rs:26:12
+   |
+26 |     let _: AssertSync<Foo> = unimplemented!(); //~ ERROR E0275
+   |            ^^^^^^^^^^^^^^^
+   |
+   = help: consider adding a `#![recursion_limit="128"]` attribute to your crate
+   = note: required because it appears within the type `std::marker::PhantomData<Foo>`
+   = note: required because it appears within the type `Bar`
+   = note: required because it appears within the type `std::marker::PhantomData<Bar>`
+   = note: required because it appears within the type `Foo`
+
+error: aborting due to previous error
+