From 3d46d095c8148e6e333e4da3e4ed8f8c63377f45 Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Mon, 15 Feb 2016 19:08:53 +0200 Subject: [PATCH] use stalled_on in all obligation types 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). --- src/librustc/middle/traits/fulfill.rs | 43 +++++++++++++++++++-------- src/librustc/middle/ty/mod.rs | 4 +-- src/test/run-pass/issue-25916.rs | 35 ++++++++++++++++++++++ 3 files changed, 68 insertions(+), 14 deletions(-) create mode 100644 src/test/run-pass/issue-25916.rs diff --git a/src/librustc/middle/traits/fulfill.rs b/src/librustc/middle/traits/fulfill.rs index c89aa4c18333c..de70cdbd29a35 100644 --- a/src/librustc/middle/traits/fulfill.rs +++ b/src/librustc/middle/traits/fulfill.rs @@ -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> +{ + 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) + } } } } diff --git a/src/librustc/middle/ty/mod.rs b/src/librustc/middle/ty/mod.rs index e3357aabd5dd5..0fd443239f8b5 100644 --- a/src/librustc/middle/ty/mod.rs +++ b/src/librustc/middle/ty/mod.rs @@ -917,7 +917,7 @@ impl<'tcx> ToPolyTraitRef<'tcx> for TraitRef<'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 @@ impl<'tcx> ToPolyTraitRef<'tcx> for PolyProjectionPredicate<'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 index 0000000000000..eb52e2e21c481 --- /dev/null +++ b/src/test/run-pass/issue-25916.rs @@ -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 or the MIT license +// , 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!(); +}