]> git.lizzy.rs Git - rust.git/commitdiff
track recursion limit when expanding existential impl trait
authorNiko Matsakis <niko@alum.mit.edu>
Wed, 17 Jan 2018 22:19:23 +0000 (17:19 -0500)
committerNiko Matsakis <niko@alum.mit.edu>
Wed, 17 Jan 2018 23:01:17 +0000 (18:01 -0500)
src/librustc/infer/region_constraints/mod.rs
src/librustc/traits/project.rs
src/librustc_mir/borrow_check/nll/type_check/mod.rs
src/test/compile-fail/impl-trait/infinite-impl-trait-issue-38064.rs [new file with mode: 0644]

index 72740dd40be2932dab0c771d6c3b9d717be5157a..68d81a2dee352c4f72becb5da5cfad63bc385164 100644 (file)
@@ -82,7 +82,7 @@ pub struct RegionConstraintCollector<'tcx> {
 /// Describes constraints between the region variables and other
 /// regions, as well as other conditions that must be verified, or
 /// assumptions that can be made.
-#[derive(Default)]
+#[derive(Debug, Default)]
 pub struct RegionConstraintData<'tcx> {
     /// Constraints of the form `A <= B`, where either `A` or `B` can
     /// be a region variable (or neither, as it happens).
index 3342d13dd6e5fa230b691ef6def7d6eebf13ccb9..d34649782ba6ad03bf88934da707552eac6db652 100644 (file)
@@ -293,9 +293,23 @@ fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
                     Reveal::UserFacing => ty,
 
                     Reveal::All => {
+                        let recursion_limit = self.tcx().sess.recursion_limit.get();
+                        if self.depth >= recursion_limit {
+                            let obligation = Obligation::with_depth(
+                                self.cause.clone(),
+                                recursion_limit,
+                                self.param_env,
+                                ty,
+                            );
+                            self.selcx.infcx().report_overflow_error(&obligation, true);
+                        }
+
                         let generic_ty = self.tcx().type_of(def_id);
                         let concrete_ty = generic_ty.subst(self.tcx(), substs);
-                        self.fold_ty(concrete_ty)
+                        self.depth += 1;
+                        let folded_ty = self.fold_ty(concrete_ty);
+                        self.depth -= 1;
+                        folded_ty
                     }
                 }
             }
index 901b73c610e3b0f6fe82d1fd7c71d7f15990379e..9dcd4435580ab71723e38699e114411c620ac523 100644 (file)
@@ -681,6 +681,8 @@ fn fully_perform_op<OP, R>(
 
         let data = self.infcx.take_and_reset_region_constraints();
         if !data.is_empty() {
+            debug!("fully_perform_op: constraints generated at {:?} are {:#?}",
+                   locations, data);
             self.constraints
                 .outlives_sets
                 .push(OutlivesSet { locations, data });
@@ -1539,6 +1541,7 @@ fn normalize<T>(&mut self, value: &T, location: Location) -> T
     where
         T: fmt::Debug + TypeFoldable<'tcx>,
     {
+        debug!("normalize(value={:?}, location={:?})", value, location);
         self.fully_perform_op(location.at_self(), |this| {
             let mut selcx = traits::SelectionContext::new(this.infcx);
             let cause = this.misc(this.last_span);
diff --git a/src/test/compile-fail/impl-trait/infinite-impl-trait-issue-38064.rs b/src/test/compile-fail/impl-trait/infinite-impl-trait-issue-38064.rs
new file mode 100644 (file)
index 0000000..abde968
--- /dev/null
@@ -0,0 +1,39 @@
+// Copyright 2016 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.
+
+// Test that attempts to construct infinite types via impl trait fail
+// in a graceful way.
+//
+// Regression test for #38064.
+
+// error-pattern:overflow evaluating the requirement `impl Quux`
+
+#![feature(conservative_impl_trait)]
+
+trait Quux {}
+
+fn foo() -> impl Quux {
+    struct Foo<T>(T);
+    impl<T> Quux for Foo<T> {}
+    Foo(bar())
+}
+
+fn bar() -> impl Quux {
+    struct Bar<T>(T);
+    impl<T> Quux for Bar<T> {}
+    Bar(foo())
+}
+
+// effectively:
+//     struct Foo(Bar);
+//     struct Bar(Foo);
+// should produce an error about infinite size
+
+fn main() { foo(); }