Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

make trait matching smarter with projections #27866

Merged
merged 4 commits into from
Aug 18, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 6 additions & 4 deletions src/librustc/middle/fast_reject.rs
Original file line number Diff line number Diff line change
Expand Up @@ -85,11 +85,13 @@ pub fn simplify_type(tcx: &ty::ctxt,
ty::TyBareFn(_, ref f) => {
Some(FunctionSimplifiedType(f.sig.0.inputs.len()))
}
ty::TyProjection(_) => {
None
}
ty::TyParam(_) => {
ty::TyProjection(_) | ty::TyParam(_) => {
if can_simplify_params {
// In normalized types, projections don't unify with
// anything. when lazy normalization happens, this
// will change. It would still be nice to have a way
// to deal with known-not-to-unify-with-anything
// projections (e.g. the likes of <__S as Encoder>::Error).
Some(ParameterSimplifiedType)
} else {
None
Expand Down
2 changes: 1 addition & 1 deletion src/librustc/middle/infer/higher_ranked/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -614,7 +614,7 @@ pub fn plug_leaks<'a,'tcx,T>(infcx: &InferCtxt<'a,'tcx>,
snapshot: &CombinedSnapshot,
value: &T)
-> T
where T : TypeFoldable<'tcx>
where T : TypeFoldable<'tcx> + ty::HasTypeFlags
{
debug_assert!(leak_check(infcx, &skol_map, snapshot).is_ok());

Expand Down
21 changes: 16 additions & 5 deletions src/librustc/middle/infer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -985,7 +985,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
snapshot: &CombinedSnapshot,
value: &T)
-> T
where T : TypeFoldable<'tcx>
where T : TypeFoldable<'tcx> + HasTypeFlags
{
/*! See `higher_ranked::plug_leaks` */

Expand Down Expand Up @@ -1256,7 +1256,9 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
}
}

pub fn resolve_type_vars_if_possible<T:TypeFoldable<'tcx>>(&self, value: &T) -> T {
pub fn resolve_type_vars_if_possible<T>(&self, value: &T) -> T
where T: TypeFoldable<'tcx> + HasTypeFlags
{
/*!
* Where possible, replaces type/int/float variables in
* `value` with their final value. Note that region variables
Expand All @@ -1266,6 +1268,9 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
* at will.
*/

if !value.needs_infer() {
return value.clone(); // avoid duplicated subst-folding
}
let mut r = resolve::OpportunisticTypeResolver::new(self);
value.fold_with(&mut r)
}
Expand Down Expand Up @@ -1456,9 +1461,15 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {

pub fn type_moves_by_default(&self, ty: Ty<'tcx>, span: Span) -> bool {
let ty = self.resolve_type_vars_if_possible(&ty);
!traits::type_known_to_meet_builtin_bound(self, ty, ty::BoundCopy, span)
// FIXME(@jroesch): should be able to use:
// ty.moves_by_default(&self.parameter_environment, span)
if ty.needs_infer() {
// this can get called from typeck (by euv), and moves_by_default
// rightly refuses to work with inference variables, but
// moves_by_default has a cache, which we want to use in other
// cases.
!traits::type_known_to_meet_builtin_bound(self, ty, ty::BoundCopy, span)
} else {
ty.moves_by_default(&self.parameter_environment, span)
}
}

pub fn node_method_ty(&self, method_call: ty::MethodCall)
Expand Down
2 changes: 1 addition & 1 deletion src/librustc/middle/traits/error_reporting.rs
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,7 @@ fn report_on_unimplemented<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
pub fn report_overflow_error<'a, 'tcx, T>(infcx: &InferCtxt<'a, 'tcx>,
obligation: &Obligation<'tcx, T>)
-> !
where T: fmt::Display + TypeFoldable<'tcx>
where T: fmt::Display + TypeFoldable<'tcx> + HasTypeFlags
{
let predicate =
infcx.resolve_type_vars_if_possible(&obligation.predicate);
Expand Down
7 changes: 3 additions & 4 deletions src/librustc/middle/traits/fulfill.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,10 @@ use middle::infer::InferCtxt;
use middle::ty::{self, RegionEscape, Ty, HasTypeFlags};
use middle::wf;

use std::collections::HashSet;
use std::fmt;
use syntax::ast;
use util::common::ErrorReported;
use util::nodemap::NodeMap;
use util::nodemap::{FnvHashSet, NodeMap};

use super::CodeAmbiguity;
use super::CodeProjectionError;
Expand All @@ -33,7 +32,7 @@ use super::Unimplemented;
use super::util::predicate_for_builtin_bound;

pub struct FulfilledPredicates<'tcx> {
set: HashSet<(RFC1214Warning, ty::Predicate<'tcx>)>
set: FnvHashSet<(RFC1214Warning, ty::Predicate<'tcx>)>
}

/// The fulfillment context is used to drive trait resolution. It
Expand Down Expand Up @@ -540,7 +539,7 @@ fn register_region_obligation<'tcx>(t_a: Ty<'tcx>,
impl<'tcx> FulfilledPredicates<'tcx> {
pub fn new() -> FulfilledPredicates<'tcx> {
FulfilledPredicates {
set: HashSet::new()
set: FnvHashSet()
}
}

Expand Down
7 changes: 7 additions & 0 deletions src/librustc/middle/traits/project.rs
Original file line number Diff line number Diff line change
Expand Up @@ -927,6 +927,13 @@ impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for Normalized<'tcx, T> {
}
}

impl<'tcx, T: HasTypeFlags> HasTypeFlags for Normalized<'tcx, T> {
fn has_type_flags(&self, flags: ty::TypeFlags) -> bool {
self.value.has_type_flags(flags) ||
self.obligations.has_type_flags(flags)
}
}

impl<'tcx, T:fmt::Debug> fmt::Debug for Normalized<'tcx, T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "Normalized({:?},{:?})",
Expand Down
57 changes: 50 additions & 7 deletions src/librustc/middle/ty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3192,6 +3192,8 @@ impl<'tcx> TraitDef<'tcx> {
}
}

/// Iterate over every impl that could possibly match the
/// self-type `self_ty`.
pub fn for_each_relevant_impl<F: FnMut(DefId)>(&self,
tcx: &ctxt<'tcx>,
self_ty: Ty<'tcx>,
Expand All @@ -3203,18 +3205,29 @@ impl<'tcx> TraitDef<'tcx> {
f(impl_def_id);
}

if let Some(simp) = fast_reject::simplify_type(tcx, self_ty, false) {
// simplify_type(.., false) basically replaces type parameters and
// projections with infer-variables. This is, of course, done on
// the impl trait-ref when it is instantiated, but not on the
// predicate trait-ref which is passed here.
//
// for example, if we match `S: Copy` against an impl like
// `impl<T:Copy> Copy for Option<T>`, we replace the type variable
// in `Option<T>` with an infer variable, to `Option<_>` (this
// doesn't actually change fast_reject output), but we don't
// replace `S` with anything - this impl of course can't be
// selected, and as there are hundreds of similar impls,
// considering them would significantly harm performance.
if let Some(simp) = fast_reject::simplify_type(tcx, self_ty, true) {
if let Some(impls) = self.nonblanket_impls.borrow().get(&simp) {
for &impl_def_id in impls {
f(impl_def_id);
}
return; // we don't need to process the other non-blanket impls
}
}

for v in self.nonblanket_impls.borrow().values() {
for &impl_def_id in v {
f(impl_def_id);
} else {
for v in self.nonblanket_impls.borrow().values() {
for &impl_def_id in v {
f(impl_def_id);
}
}
}
}
Expand Down Expand Up @@ -7266,6 +7279,24 @@ impl<'tcx,T:HasTypeFlags> HasTypeFlags for VecPerParamSpace<T> {
}
}

impl HasTypeFlags for abi::Abi {
fn has_type_flags(&self, _flags: TypeFlags) -> bool {
false
}
}

impl HasTypeFlags for ast::Unsafety {
fn has_type_flags(&self, _flags: TypeFlags) -> bool {
false
}
}

impl HasTypeFlags for BuiltinBounds {
fn has_type_flags(&self, _flags: TypeFlags) -> bool {
false
}
}

impl<'tcx> HasTypeFlags for ClosureTy<'tcx> {
fn has_type_flags(&self, flags: TypeFlags) -> bool {
self.sig.has_type_flags(flags)
Expand All @@ -7278,6 +7309,12 @@ impl<'tcx> HasTypeFlags for ClosureUpvar<'tcx> {
}
}

impl<'tcx> HasTypeFlags for ExistentialBounds<'tcx> {
fn has_type_flags(&self, flags: TypeFlags) -> bool {
self.projection_bounds.has_type_flags(flags)
}
}

impl<'tcx> HasTypeFlags for ty::InstantiatedPredicates<'tcx> {
fn has_type_flags(&self, flags: TypeFlags) -> bool {
self.predicates.has_type_flags(flags)
Expand Down Expand Up @@ -7353,6 +7390,12 @@ impl<'tcx> HasTypeFlags for Ty<'tcx> {
}
}

impl<'tcx> HasTypeFlags for TypeAndMut<'tcx> {
fn has_type_flags(&self, flags: TypeFlags) -> bool {
self.ty.has_type_flags(flags)
}
}

impl<'tcx> HasTypeFlags for TraitRef<'tcx> {
fn has_type_flags(&self, flags: TypeFlags) -> bool {
self.substs.has_type_flags(flags)
Expand Down
4 changes: 2 additions & 2 deletions src/librustc/middle/ty_relate/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
//! type equality, etc.

use middle::subst::{ErasedRegions, NonerasedRegions, ParamSpace, Substs};
use middle::ty::{self, Ty, TypeError};
use middle::ty::{self, HasTypeFlags, Ty, TypeError};
use middle::ty_fold::TypeFoldable;
use std::rc::Rc;
use syntax::abi;
Expand Down Expand Up @@ -78,7 +78,7 @@ pub trait TypeRelation<'a,'tcx> : Sized {
where T: Relate<'a,'tcx>;
}

pub trait Relate<'a,'tcx>: TypeFoldable<'tcx> {
pub trait Relate<'a,'tcx>: TypeFoldable<'tcx> + HasTypeFlags {
fn relate<R:TypeRelation<'a,'tcx>>(relation: &mut R,
a: &Self,
b: &Self)
Expand Down