Skip to content

Commit

Permalink
Rollup merge of rust-lang#23895 - nikomatsakis:fn-trait-inheritance-a…
Browse files Browse the repository at this point in the history
…dd-impls, r=pnkfelix

The primary purpose of this PR is to add blanket impls for the `Fn` traits of the following (simplified) form:

    impl<F:Fn> Fn for &F
    impl<F:FnMut> FnMut for &mut F

However, this wound up requiring two changes:

1. A slight hack so that `x()` where `x: &mut F` is translated to `FnMut::call_mut(&mut *x, ())` vs `FnMut::call_mut(&mut x, ())`. This is achieved by just autoderef'ing one time when calling something whose type is `&F` or `&mut F`.
2. Making the infinite recursion test in trait matching a bit more tailored. This involves adding a notion of "matching" types that looks to see if types are potentially unifiable (it's an approximation).

The PR also includes various small refactorings to the inference code that are aimed at moving the unification and other code into a library (I've got that particular change in a branch, these changes just lead the way there by removing unnecessary dependencies between the compiler and the more general unification code). 

Note that per rust-lang/rfcs#1023, adding impls like these would be a breaking change in the future. 

cc @japaric
cc @alexcrichton 
cc @aturon 

Fixes rust-lang#23015.
  • Loading branch information
Manishearth committed Apr 1, 2015
2 parents 9eb0bab + 11111bb commit debac97
Show file tree
Hide file tree
Showing 35 changed files with 1,627 additions and 1,270 deletions.
49 changes: 49 additions & 0 deletions src/libcore/ops.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1145,3 +1145,52 @@ pub trait FnOnce<Args> {
/// This is called when the call operator is used.
extern "rust-call" fn call_once(self, args: Args) -> Self::Output;
}

#[cfg(not(stage0))]
mod impls {
use marker::Sized;
use super::{Fn, FnMut, FnOnce};

impl<'a,A,F:?Sized> Fn<A> for &'a F
where F : Fn<A>
{
extern "rust-call" fn call(&self, args: A) -> F::Output {
(**self).call(args)
}
}

impl<'a,A,F:?Sized> FnMut<A> for &'a F
where F : Fn<A>
{
extern "rust-call" fn call_mut(&mut self, args: A) -> F::Output {
(**self).call(args)
}
}

impl<'a,A,F:?Sized> FnOnce<A> for &'a F
where F : Fn<A>
{
type Output = F::Output;

extern "rust-call" fn call_once(self, args: A) -> F::Output {
(*self).call(args)
}
}

impl<'a,A,F:?Sized> FnMut<A> for &'a mut F
where F : FnMut<A>
{
extern "rust-call" fn call_mut(&mut self, args: A) -> F::Output {
(*self).call_mut(args)
}
}

impl<'a,A,F:?Sized> FnOnce<A> for &'a mut F
where F : FnMut<A>
{
type Output = F::Output;
extern "rust-call" fn call_once(mut self, args: A) -> F::Output {
(*self).call_mut(args)
}
}
}
2 changes: 2 additions & 0 deletions src/librustc/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,8 @@ pub mod middle {
pub mod traits;
pub mod ty;
pub mod ty_fold;
pub mod ty_match;
pub mod ty_relate;
pub mod ty_walk;
pub mod weak_lang_items;
}
Expand Down
93 changes: 43 additions & 50 deletions src/librustc/middle/infer/bivariate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,66 +25,54 @@
//! In particular, it might be enough to say (A,B) are bivariant for
//! all (A,B).

use middle::ty::BuiltinBounds;
use super::combine::{self, CombineFields};
use super::type_variable::{BiTo};

use middle::ty::{self, Ty};
use middle::ty::TyVar;
use middle::infer::combine::*;
use middle::infer::cres;
use middle::infer::type_variable::BiTo;
use util::ppaux::Repr;
use middle::ty_relate::{Relate, RelateResult, TypeRelation};
use util::ppaux::{Repr};

pub struct Bivariate<'f, 'tcx: 'f> {
fields: CombineFields<'f, 'tcx>
pub struct Bivariate<'a, 'tcx: 'a> {
fields: CombineFields<'a, 'tcx>
}

#[allow(non_snake_case)]
pub fn Bivariate<'f, 'tcx>(cf: CombineFields<'f, 'tcx>) -> Bivariate<'f, 'tcx> {
Bivariate { fields: cf }
impl<'a, 'tcx> Bivariate<'a, 'tcx> {
pub fn new(fields: CombineFields<'a, 'tcx>) -> Bivariate<'a, 'tcx> {
Bivariate { fields: fields }
}
}

impl<'f, 'tcx> Combine<'tcx> for Bivariate<'f, 'tcx> {
fn tag(&self) -> String { "Bivariate".to_string() }
fn fields<'a>(&'a self) -> &'a CombineFields<'a, 'tcx> { &self.fields }
impl<'a, 'tcx> TypeRelation<'a, 'tcx> for Bivariate<'a, 'tcx> {
fn tag(&self) -> &'static str { "Bivariate" }

fn tys_with_variance(&self, v: ty::Variance, a: Ty<'tcx>, b: Ty<'tcx>)
-> cres<'tcx, Ty<'tcx>>
{
match v {
ty::Invariant => self.equate().tys(a, b),
ty::Covariant => self.tys(a, b),
ty::Contravariant => self.tys(a, b),
ty::Bivariant => self.tys(a, b),
}
}
fn tcx(&self) -> &'a ty::ctxt<'tcx> { self.fields.tcx() }

fn regions_with_variance(&self, v: ty::Variance, a: ty::Region, b: ty::Region)
-> cres<'tcx, ty::Region>
{
match v {
ty::Invariant => self.equate().regions(a, b),
ty::Covariant => self.regions(a, b),
ty::Contravariant => self.regions(a, b),
ty::Bivariant => self.regions(a, b),
}
}
fn a_is_expected(&self) -> bool { self.fields.a_is_expected }

fn regions(&self, a: ty::Region, _: ty::Region) -> cres<'tcx, ty::Region> {
Ok(a)
}

fn builtin_bounds(&self,
a: BuiltinBounds,
b: BuiltinBounds)
-> cres<'tcx, BuiltinBounds>
fn relate_with_variance<T:Relate<'a,'tcx>>(&mut self,
variance: ty::Variance,
a: &T,
b: &T)
-> RelateResult<'tcx, T>
{
if a != b {
Err(ty::terr_builtin_bounds(expected_found(self, a, b)))
} else {
Ok(a)
match variance {
// If we have Foo<A> and Foo is invariant w/r/t A,
// and we want to assert that
//
// Foo<A> <: Foo<B> ||
// Foo<B> <: Foo<A>
//
// then still A must equal B.
ty::Invariant => self.relate(a, b),

ty::Covariant => self.relate(a, b),
ty::Bivariant => self.relate(a, b),
ty::Contravariant => self.relate(a, b),
}
}

fn tys(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> cres<'tcx, Ty<'tcx>> {
fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
debug!("{}.tys({}, {})", self.tag(),
a.repr(self.fields.infcx.tcx), b.repr(self.fields.infcx.tcx));
if a == b { return Ok(a); }
Expand All @@ -109,17 +97,22 @@ impl<'f, 'tcx> Combine<'tcx> for Bivariate<'f, 'tcx> {
}

_ => {
super_tys(self, a, b)
combine::super_combine_tys(self.fields.infcx, self, a, b)
}
}
}

fn binders<T>(&self, a: &ty::Binder<T>, b: &ty::Binder<T>) -> cres<'tcx, ty::Binder<T>>
where T : Combineable<'tcx>
fn regions(&mut self, a: ty::Region, _: ty::Region) -> RelateResult<'tcx, ty::Region> {
Ok(a)
}

fn binders<T>(&mut self, a: &ty::Binder<T>, b: &ty::Binder<T>)
-> RelateResult<'tcx, ty::Binder<T>>
where T: Relate<'a,'tcx>
{
let a1 = ty::erase_late_bound_regions(self.tcx(), a);
let b1 = ty::erase_late_bound_regions(self.tcx(), b);
let c = try!(Combineable::combine(self, &a1, &b1));
let c = try!(self.relate(&a1, &b1));
Ok(ty::Binder(c))
}
}
Loading

0 comments on commit debac97

Please sign in to comment.