mirror of
https://github.com/rust-lang/rust.git
synced 2025-06-07 12:48:30 +00:00
Auto merge of #31680 - arielb1:fast-fulfill, r=nikomatsakis
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
This commit is contained in:
commit
57c357d891
@ -10,7 +10,7 @@
|
|||||||
|
|
||||||
use dep_graph::DepGraph;
|
use dep_graph::DepGraph;
|
||||||
use middle::infer::InferCtxt;
|
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 rustc_data_structures::obligation_forest::{Backtrace, ObligationForest, Error};
|
||||||
use std::iter;
|
use std::iter;
|
||||||
use syntax::ast;
|
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:
|
/// Processes a predicate obligation and returns either:
|
||||||
/// - `Ok(Some(v))` if the predicate is true, presuming that `v` are also true
|
/// - `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
|
/// - `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
|
// doing more work yet
|
||||||
if !pending_obligation.stalled_on.is_empty() {
|
if !pending_obligation.stalled_on.is_empty() {
|
||||||
if pending_obligation.stalled_on.iter().all(|&ty| {
|
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
|
resolved_ty == ty // nothing changed here
|
||||||
}) {
|
}) {
|
||||||
debug!("process_predicate: pending obligation {:?} still stalled on {:?}",
|
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
|
// of its type, and those types are resolved at
|
||||||
// the same time.
|
// the same time.
|
||||||
pending_obligation.stalled_on =
|
pending_obligation.stalled_on =
|
||||||
data.skip_binder() // ok b/c this check doesn't care about regions
|
trait_ref_type_vars(selcx, data.to_poly_trait_ref());
|
||||||
.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();
|
|
||||||
|
|
||||||
debug!("process_predicate: pending obligation {:?} now stalled on {:?}",
|
debug!("process_predicate: pending obligation {:?} now stalled on {:?}",
|
||||||
selcx.infcx().resolve_type_vars_if_possible(obligation),
|
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) => {
|
ty::Predicate::Projection(ref data) => {
|
||||||
let project_obligation = obligation.with(data.clone());
|
let project_obligation = obligation.with(data.clone());
|
||||||
match project::poly_project_and_unify_type(selcx, &project_obligation) {
|
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),
|
Ok(v) => Ok(v),
|
||||||
Err(e) => Err(CodeProjectionError(e))
|
Err(e) => Err(CodeProjectionError(e))
|
||||||
}
|
}
|
||||||
@ -582,8 +595,14 @@ fn process_predicate1<'a,'tcx>(selcx: &mut SelectionContext<'a,'tcx>,
|
|||||||
}
|
}
|
||||||
|
|
||||||
ty::Predicate::WellFormed(ty) => {
|
ty::Predicate::WellFormed(ty) => {
|
||||||
Ok(ty::wf::obligations(selcx.infcx(), obligation.cause.body_id,
|
match ty::wf::obligations(selcx.infcx(), obligation.cause.body_id,
|
||||||
ty, obligation.cause.span))
|
ty, obligation.cause.span) {
|
||||||
|
None => {
|
||||||
|
pending_obligation.stalled_on = vec![ty];
|
||||||
|
Ok(None)
|
||||||
|
}
|
||||||
|
s => Ok(s)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -917,7 +917,7 @@ impl<'tcx> ToPolyTraitRef<'tcx> for TraitRef<'tcx> {
|
|||||||
|
|
||||||
impl<'tcx> ToPolyTraitRef<'tcx> for PolyTraitPredicate<'tcx> {
|
impl<'tcx> ToPolyTraitRef<'tcx> for PolyTraitPredicate<'tcx> {
|
||||||
fn to_poly_trait_ref(&self) -> PolyTraitRef<'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
|
// This is because here `self` has a `Binder` and so does our
|
||||||
// return value, so we are preserving the number of binding
|
// return value, so we are preserving the number of binding
|
||||||
// levels.
|
// levels.
|
||||||
ty::Binder(self.0.projection_ty.trait_ref.clone())
|
ty::Binder(self.0.projection_ty.trait_ref)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
35
src/test/run-pass/issue-25916.rs
Normal file
35
src/test/run-pass/issue-25916.rs
Normal file
@ -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!();
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user