From 80b8c808baaba629e73440abf52ee4bbfdb5c0f8 Mon Sep 17 00:00:00 2001 From: Peter Hrvola Date: Sat, 27 Jan 2018 12:02:45 +0100 Subject: [PATCH] Optimized error reporting for recursive requirements #47720 --- src/librustc/traits/error_reporting.rs | 40 ++++++++++++++++++----- src/test/ui/recursive-requirements.rs | 27 +++++++++++++++ src/test/ui/recursive-requirements.stderr | 14 ++++++++ 3 files changed, 72 insertions(+), 9 deletions(-) create mode 100644 src/test/ui/recursive-requirements.rs create mode 100644 src/test/ui/recursive-requirements.stderr diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index 42200a3a44728..dc8fcbb597414 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -1194,13 +1194,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(&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; @@ -1292,12 +1294,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); @@ -1307,8 +1314,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( @@ -1327,6 +1335,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 0000000000000..2c0f0338b2d15 --- /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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::marker::PhantomData; + +struct AssertSync(PhantomData); + +pub struct Foo { + bar: *const Bar, + phantom: PhantomData, +} + +pub struct Bar { + foo: *const Foo, + phantom: PhantomData, +} + +fn main() { + let _: AssertSync = unimplemented!(); //~ ERROR E0275 +} diff --git a/src/test/ui/recursive-requirements.stderr b/src/test/ui/recursive-requirements.stderr new file mode 100644 index 0000000000000..8cf2c65b1e25c --- /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 = 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` + = note: required because it appears within the type `Bar` + = note: required because it appears within the type `std::marker::PhantomData` + = note: required because it appears within the type `Foo` + +error: aborting due to previous error +