Skip to content

Commit debac97

Browse files
committed
Rollup merge of rust-lang#23895 - nikomatsakis:fn-trait-inheritance-add-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.
2 parents 9eb0bab + 11111bb commit debac97

35 files changed

+1627
-1270
lines changed

src/libcore/ops.rs

+49
Original file line numberDiff line numberDiff line change
@@ -1145,3 +1145,52 @@ pub trait FnOnce<Args> {
11451145
/// This is called when the call operator is used.
11461146
extern "rust-call" fn call_once(self, args: Args) -> Self::Output;
11471147
}
1148+
1149+
#[cfg(not(stage0))]
1150+
mod impls {
1151+
use marker::Sized;
1152+
use super::{Fn, FnMut, FnOnce};
1153+
1154+
impl<'a,A,F:?Sized> Fn<A> for &'a F
1155+
where F : Fn<A>
1156+
{
1157+
extern "rust-call" fn call(&self, args: A) -> F::Output {
1158+
(**self).call(args)
1159+
}
1160+
}
1161+
1162+
impl<'a,A,F:?Sized> FnMut<A> for &'a F
1163+
where F : Fn<A>
1164+
{
1165+
extern "rust-call" fn call_mut(&mut self, args: A) -> F::Output {
1166+
(**self).call(args)
1167+
}
1168+
}
1169+
1170+
impl<'a,A,F:?Sized> FnOnce<A> for &'a F
1171+
where F : Fn<A>
1172+
{
1173+
type Output = F::Output;
1174+
1175+
extern "rust-call" fn call_once(self, args: A) -> F::Output {
1176+
(*self).call(args)
1177+
}
1178+
}
1179+
1180+
impl<'a,A,F:?Sized> FnMut<A> for &'a mut F
1181+
where F : FnMut<A>
1182+
{
1183+
extern "rust-call" fn call_mut(&mut self, args: A) -> F::Output {
1184+
(*self).call_mut(args)
1185+
}
1186+
}
1187+
1188+
impl<'a,A,F:?Sized> FnOnce<A> for &'a mut F
1189+
where F : FnMut<A>
1190+
{
1191+
type Output = F::Output;
1192+
extern "rust-call" fn call_once(mut self, args: A) -> F::Output {
1193+
(*self).call_mut(args)
1194+
}
1195+
}
1196+
}

src/librustc/lib.rs

+2
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,8 @@ pub mod middle {
120120
pub mod traits;
121121
pub mod ty;
122122
pub mod ty_fold;
123+
pub mod ty_match;
124+
pub mod ty_relate;
123125
pub mod ty_walk;
124126
pub mod weak_lang_items;
125127
}

src/librustc/middle/infer/bivariate.rs

+43-50
Original file line numberDiff line numberDiff line change
@@ -25,66 +25,54 @@
2525
//! In particular, it might be enough to say (A,B) are bivariant for
2626
//! all (A,B).
2727
28-
use middle::ty::BuiltinBounds;
28+
use super::combine::{self, CombineFields};
29+
use super::type_variable::{BiTo};
30+
2931
use middle::ty::{self, Ty};
3032
use middle::ty::TyVar;
31-
use middle::infer::combine::*;
32-
use middle::infer::cres;
33-
use middle::infer::type_variable::BiTo;
34-
use util::ppaux::Repr;
33+
use middle::ty_relate::{Relate, RelateResult, TypeRelation};
34+
use util::ppaux::{Repr};
3535

36-
pub struct Bivariate<'f, 'tcx: 'f> {
37-
fields: CombineFields<'f, 'tcx>
36+
pub struct Bivariate<'a, 'tcx: 'a> {
37+
fields: CombineFields<'a, 'tcx>
3838
}
3939

40-
#[allow(non_snake_case)]
41-
pub fn Bivariate<'f, 'tcx>(cf: CombineFields<'f, 'tcx>) -> Bivariate<'f, 'tcx> {
42-
Bivariate { fields: cf }
40+
impl<'a, 'tcx> Bivariate<'a, 'tcx> {
41+
pub fn new(fields: CombineFields<'a, 'tcx>) -> Bivariate<'a, 'tcx> {
42+
Bivariate { fields: fields }
43+
}
4344
}
4445

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

49-
fn tys_with_variance(&self, v: ty::Variance, a: Ty<'tcx>, b: Ty<'tcx>)
50-
-> cres<'tcx, Ty<'tcx>>
51-
{
52-
match v {
53-
ty::Invariant => self.equate().tys(a, b),
54-
ty::Covariant => self.tys(a, b),
55-
ty::Contravariant => self.tys(a, b),
56-
ty::Bivariant => self.tys(a, b),
57-
}
58-
}
49+
fn tcx(&self) -> &'a ty::ctxt<'tcx> { self.fields.tcx() }
5950

60-
fn regions_with_variance(&self, v: ty::Variance, a: ty::Region, b: ty::Region)
61-
-> cres<'tcx, ty::Region>
62-
{
63-
match v {
64-
ty::Invariant => self.equate().regions(a, b),
65-
ty::Covariant => self.regions(a, b),
66-
ty::Contravariant => self.regions(a, b),
67-
ty::Bivariant => self.regions(a, b),
68-
}
69-
}
51+
fn a_is_expected(&self) -> bool { self.fields.a_is_expected }
7052

71-
fn regions(&self, a: ty::Region, _: ty::Region) -> cres<'tcx, ty::Region> {
72-
Ok(a)
73-
}
74-
75-
fn builtin_bounds(&self,
76-
a: BuiltinBounds,
77-
b: BuiltinBounds)
78-
-> cres<'tcx, BuiltinBounds>
53+
fn relate_with_variance<T:Relate<'a,'tcx>>(&mut self,
54+
variance: ty::Variance,
55+
a: &T,
56+
b: &T)
57+
-> RelateResult<'tcx, T>
7958
{
80-
if a != b {
81-
Err(ty::terr_builtin_bounds(expected_found(self, a, b)))
82-
} else {
83-
Ok(a)
59+
match variance {
60+
// If we have Foo<A> and Foo is invariant w/r/t A,
61+
// and we want to assert that
62+
//
63+
// Foo<A> <: Foo<B> ||
64+
// Foo<B> <: Foo<A>
65+
//
66+
// then still A must equal B.
67+
ty::Invariant => self.relate(a, b),
68+
69+
ty::Covariant => self.relate(a, b),
70+
ty::Bivariant => self.relate(a, b),
71+
ty::Contravariant => self.relate(a, b),
8472
}
8573
}
8674

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

11199
_ => {
112-
super_tys(self, a, b)
100+
combine::super_combine_tys(self.fields.infcx, self, a, b)
113101
}
114102
}
115103
}
116104

117-
fn binders<T>(&self, a: &ty::Binder<T>, b: &ty::Binder<T>) -> cres<'tcx, ty::Binder<T>>
118-
where T : Combineable<'tcx>
105+
fn regions(&mut self, a: ty::Region, _: ty::Region) -> RelateResult<'tcx, ty::Region> {
106+
Ok(a)
107+
}
108+
109+
fn binders<T>(&mut self, a: &ty::Binder<T>, b: &ty::Binder<T>)
110+
-> RelateResult<'tcx, ty::Binder<T>>
111+
where T: Relate<'a,'tcx>
119112
{
120113
let a1 = ty::erase_late_bound_regions(self.tcx(), a);
121114
let b1 = ty::erase_late_bound_regions(self.tcx(), b);
122-
let c = try!(Combineable::combine(self, &a1, &b1));
115+
let c = try!(self.relate(&a1, &b1));
123116
Ok(ty::Binder(c))
124117
}
125118
}

0 commit comments

Comments
 (0)