]> git.lizzy.rs Git - rust.git/commitdiff
Auto merge of #31680 - arielb1:fast-fulfill, r=nikomatsakis
authorbors <bors@rust-lang.org>
Tue, 16 Feb 2016 22:35:09 +0000 (22:35 +0000)
committerbors <bors@rust-lang.org>
Tue, 16 Feb 2016 22:35:09 +0000 (22:35 +0000)
this improves typeck performance by 5% (LLVM times are still huge).

Basically fixes #25916 (still O(n^2), but the example takes <1s to
compile).

r? @nikomatsakis

src/librustc/middle/traits/fulfill.rs
src/librustc/middle/ty/mod.rs
src/test/run-pass/issue-25916.rs [new file with mode: 0644]

index c89aa4c18333cde85362b2050c9bb86f40a59c54..de70cdbd29a354849607c3deb4f5e712a50aed07 100644 (file)
@@ -10,7 +10,7 @@
 
 use dep_graph::DepGraph;
 use middle::infer::InferCtxt;
-use middle::ty::{self, Ty, TypeFoldable};
+use middle::ty::{self, Ty, TypeFoldable, ToPolyTraitRef};
 use rustc_data_structures::obligation_forest::{Backtrace, ObligationForest, Error};
 use std::iter;
 use syntax::ast;
@@ -417,6 +417,21 @@ fn process_predicate<'a,'tcx>(selcx: &mut SelectionContext<'a,'tcx>,
     }
 }
 
+
+/// Return the set of type variables contained in a trait ref
+fn trait_ref_type_vars<'a, 'tcx>(selcx: &mut SelectionContext<'a, 'tcx>,
+                                 t: ty::PolyTraitRef<'tcx>) -> Vec<Ty<'tcx>>
+{
+    t.skip_binder() // ok b/c this check doesn't care about regions
+     .input_types()
+     .iter()
+     .map(|t| selcx.infcx().resolve_type_vars_if_possible(t))
+     .filter(|t| t.has_infer_types())
+     .flat_map(|t| t.walk())
+     .filter(|t| match t.sty { ty::TyInfer(_) => true, _ => false })
+     .collect()
+}
+
 /// Processes a predicate obligation and returns either:
 /// - `Ok(Some(v))` if the predicate is true, presuming that `v` are also true
 /// - `Ok(None)` if we don't have enough info to be sure
@@ -433,7 +448,7 @@ fn process_predicate1<'a,'tcx>(selcx: &mut SelectionContext<'a,'tcx>,
     // doing more work yet
     if !pending_obligation.stalled_on.is_empty() {
         if pending_obligation.stalled_on.iter().all(|&ty| {
-            let resolved_ty = selcx.infcx().resolve_type_vars_if_possible(&ty);
+            let resolved_ty = selcx.infcx().shallow_resolve(&ty);
             resolved_ty == ty // nothing changed here
         }) {
             debug!("process_predicate: pending obligation {:?} still stalled on {:?}",
@@ -493,14 +508,7 @@ fn process_predicate1<'a,'tcx>(selcx: &mut SelectionContext<'a,'tcx>,
                     // of its type, and those types are resolved at
                     // the same time.
                     pending_obligation.stalled_on =
-                        data.skip_binder() // ok b/c this check doesn't care about regions
-                        .input_types()
-                        .iter()
-                        .map(|t| selcx.infcx().resolve_type_vars_if_possible(t))
-                        .filter(|t| t.has_infer_types())
-                        .flat_map(|t| t.walk())
-                        .filter(|t| match t.sty { ty::TyInfer(_) => true, _ => false })
-                        .collect();
+                        trait_ref_type_vars(selcx, data.to_poly_trait_ref());
 
                     debug!("process_predicate: pending obligation {:?} now stalled on {:?}",
                            selcx.infcx().resolve_type_vars_if_possible(obligation),
@@ -568,6 +576,11 @@ fn process_predicate1<'a,'tcx>(selcx: &mut SelectionContext<'a,'tcx>,
         ty::Predicate::Projection(ref data) => {
             let project_obligation = obligation.with(data.clone());
             match project::poly_project_and_unify_type(selcx, &project_obligation) {
+                Ok(None) => {
+                    pending_obligation.stalled_on =
+                        trait_ref_type_vars(selcx, data.to_poly_trait_ref());
+                    Ok(None)
+                }
                 Ok(v) => Ok(v),
                 Err(e) => Err(CodeProjectionError(e))
             }
@@ -582,8 +595,14 @@ fn process_predicate1<'a,'tcx>(selcx: &mut SelectionContext<'a,'tcx>,
         }
 
         ty::Predicate::WellFormed(ty) => {
-            Ok(ty::wf::obligations(selcx.infcx(), obligation.cause.body_id,
-                                   ty, obligation.cause.span))
+            match ty::wf::obligations(selcx.infcx(), obligation.cause.body_id,
+                                      ty, obligation.cause.span) {
+                None => {
+                    pending_obligation.stalled_on = vec![ty];
+                    Ok(None)
+                }
+                s => Ok(s)
+            }
         }
     }
 }
index e3357aabd5dd568aa2a739874859288e4c9e5e84..0fd443239f8b578c2503a9d11a44004ac721a854 100644 (file)
@@ -917,7 +917,7 @@ fn to_poly_trait_ref(&self) -> PolyTraitRef<'tcx> {
 
 impl<'tcx> ToPolyTraitRef<'tcx> for PolyTraitPredicate<'tcx> {
     fn to_poly_trait_ref(&self) -> PolyTraitRef<'tcx> {
-        self.map_bound_ref(|trait_pred| trait_pred.trait_ref.clone())
+        self.map_bound_ref(|trait_pred| trait_pred.trait_ref)
     }
 }
 
@@ -928,7 +928,7 @@ fn to_poly_trait_ref(&self) -> PolyTraitRef<'tcx> {
         // This is because here `self` has a `Binder` and so does our
         // return value, so we are preserving the number of binding
         // levels.
-        ty::Binder(self.0.projection_ty.trait_ref.clone())
+        ty::Binder(self.0.projection_ty.trait_ref)
     }
 }
 
diff --git a/src/test/run-pass/issue-25916.rs b/src/test/run-pass/issue-25916.rs
new file mode 100644 (file)
index 0000000..eb52e2e
--- /dev/null
@@ -0,0 +1,35 @@
+// 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.
+
+fn main() {
+    macro_rules! f {
+        () => { 0 + 0 }
+    }
+    // 16 per line
+    f!();f!();f!();f!();f!();f!();f!();f!();f!();f!();f!();f!();f!();f!();f!();f!();
+    f!();f!();f!();f!();f!();f!();f!();f!();f!();f!();f!();f!();f!();f!();f!();f!();
+    f!();f!();f!();f!();f!();f!();f!();f!();f!();f!();f!();f!();f!();f!();f!();f!();
+    f!();f!();f!();f!();f!();f!();f!();f!();f!();f!();f!();f!();f!();f!();f!();f!();
+
+    f!();f!();f!();f!();f!();f!();f!();f!();f!();f!();f!();f!();f!();f!();f!();f!();
+    f!();f!();f!();f!();f!();f!();f!();f!();f!();f!();f!();f!();f!();f!();f!();f!();
+    f!();f!();f!();f!();f!();f!();f!();f!();f!();f!();f!();f!();f!();f!();f!();f!();
+    f!();f!();f!();f!();f!();f!();f!();f!();f!();f!();f!();f!();f!();f!();f!();f!();
+
+    f!();f!();f!();f!();f!();f!();f!();f!();f!();f!();f!();f!();f!();f!();f!();f!();
+    f!();f!();f!();f!();f!();f!();f!();f!();f!();f!();f!();f!();f!();f!();f!();f!();
+    f!();f!();f!();f!();f!();f!();f!();f!();f!();f!();f!();f!();f!();f!();f!();f!();
+    f!();f!();f!();f!();f!();f!();f!();f!();f!();f!();f!();f!();f!();f!();f!();f!();
+
+    f!();f!();f!();f!();f!();f!();f!();f!();f!();f!();f!();f!();f!();f!();f!();f!();
+    f!();f!();f!();f!();f!();f!();f!();f!();f!();f!();f!();f!();f!();f!();f!();f!();
+    f!();f!();f!();f!();f!();f!();f!();f!();f!();f!();f!();f!();f!();f!();f!();f!();
+    f!();f!();f!();f!();f!();f!();f!();f!();f!();f!();f!();f!();f!();f!();f!();f!();
+}