Skip to content

Commit

Permalink
Stabilize nested self receivers
Browse files Browse the repository at this point in the history
Previously, only Self, &Self, &mut Self, Arc<Self>, Rc<Self>,
and Box<Self> were available as stable method receivers.

This commit stabilizes nested uses of all the above types.
However, nested receivers remain non-object-safe.
  • Loading branch information
cramertj committed Nov 26, 2019
1 parent 797fd92 commit 2083e2a
Show file tree
Hide file tree
Showing 58 changed files with 214 additions and 319 deletions.
79 changes: 48 additions & 31 deletions src/librustc_typeck/check/wfcheck.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use crate::check::{Inherited, FnCtxt};
use crate::constrained_generic_params::{identify_constrained_generic_params, Parameter};

use crate::hir::def_id::DefId;
use rustc::traits::{self, ObligationCauseCode};
use rustc::traits::{self, ObligationCause, ObligationCauseCode};
use rustc::ty::{self, Ty, TyCtxt, GenericParamDefKind, TypeFoldable, ToPredicate};
use rustc::ty::subst::{Subst, InternalSubsts};
use rustc::util::nodemap::{FxHashSet, FxHashMap};
Expand Down Expand Up @@ -895,6 +895,11 @@ fn receiver_is_valid<'fcx, 'tcx>(
// The first type is `receiver_ty`, which we know its not equal to `self_ty`; skip it.
autoderef.next();

let receiver_trait_def_id = fcx.tcx.require_lang_item(
lang_items::ReceiverTraitLangItem,
None,
);

// Keep dereferencing `receiver_ty` until we get to `self_ty`.
loop {
if let Some((potential_self_ty, _)) = autoderef.next() {
Expand All @@ -911,6 +916,19 @@ fn receiver_is_valid<'fcx, 'tcx>(
}

break
} else {
// Without `feature(arbitrary_self_types)`, we require that each step in the
// deref chain implement `receiver`
if !arbitrary_self_types_enabled
&& !receiver_is_implemented(
fcx,
receiver_trait_def_id,
cause.clone(),
potential_self_ty,
)
{
return false
}
}
} else {
debug!("receiver_is_valid: type `{:?}` does not deref to `{:?}`",
Expand All @@ -919,43 +937,42 @@ fn receiver_is_valid<'fcx, 'tcx>(
// unecessary errors (#58712).
return receiver_ty.references_error();
}

// Without the `arbitrary_self_types` feature, `receiver_ty` must directly deref to
// `self_ty`. Enforce this by only doing one iteration of the loop.
if !arbitrary_self_types_enabled {
return false
}
}

// Without `feature(arbitrary_self_types)`, we require that `receiver_ty` implements `Receiver`.
if !arbitrary_self_types_enabled {
let trait_def_id = match fcx.tcx.lang_items().receiver_trait() {
Some(did) => did,
None => {
debug!("receiver_is_valid: missing Receiver trait");
return false
}
};
if !arbitrary_self_types_enabled
&& !receiver_is_implemented(fcx, receiver_trait_def_id, cause.clone(), receiver_ty)
{
return false
}

let trait_ref = ty::TraitRef{
def_id: trait_def_id,
substs: fcx.tcx.mk_substs_trait(receiver_ty, &[]),
};
true
}

fn receiver_is_implemented(
fcx: &FnCtxt<'_, 'tcx>,
receiver_trait_def_id: DefId,
cause: ObligationCause<'tcx>,
receiver_ty: Ty<'tcx>,
) -> bool {
let trait_ref = ty::TraitRef{
def_id: receiver_trait_def_id,
substs: fcx.tcx.mk_substs_trait(receiver_ty, &[]),
};

let obligation = traits::Obligation::new(
cause,
fcx.param_env,
trait_ref.to_predicate()
);
let obligation = traits::Obligation::new(
cause,
fcx.param_env,
trait_ref.to_predicate()
);

if !fcx.predicate_must_hold_modulo_regions(&obligation) {
debug!("receiver_is_valid: type `{:?}` does not implement `Receiver` trait",
receiver_ty);
return false
}
if fcx.predicate_must_hold_modulo_regions(&obligation) {
true
} else {
debug!("receiver_is_implemented: type `{:?}` does not implement `Receiver` trait",
receiver_ty);
false
}

true
}

fn check_variances_for_type_defn<'tcx>(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
error[E0038]: the trait `Foo` cannot be made into an object
--> $DIR/arbitrary-self-types-not-object-safe.rs:34:32
--> $DIR/arbitrary-self-types-not-object-safe.rs:33:32
|
LL | fn foo(self: &Rc<Self>) -> usize;
| --- method `foo`'s `self` parameter cannot be dispatched on
Expand All @@ -8,7 +8,7 @@ LL | let x = Rc::new(5usize) as Rc<dyn Foo>;
| ^^^^^^^^^^^ the trait `Foo` cannot be made into an object

error[E0038]: the trait `Foo` cannot be made into an object
--> $DIR/arbitrary-self-types-not-object-safe.rs:34:13
--> $DIR/arbitrary-self-types-not-object-safe.rs:33:13
|
LL | fn foo(self: &Rc<Self>) -> usize;
| --- method `foo`'s `self` parameter cannot be dispatched on
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
error[E0038]: the trait `Foo` cannot be made into an object
--> $DIR/arbitrary-self-types-not-object-safe.rs:34:13
--> $DIR/arbitrary-self-types-not-object-safe.rs:33:13
|
LL | fn foo(self: &Rc<Self>) -> usize;
| --- method `foo`'s `self` parameter cannot be dispatched on
Expand Down
1 change: 0 additions & 1 deletion src/test/ui/self/arbitrary-self-types-not-object-safe.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
// revisions: curr object_safe_for_dispatch

#![cfg_attr(object_safe_for_dispatch, feature(object_safe_for_dispatch))]
#![feature(arbitrary_self_types)]

use std::rc::Rc;

Expand Down
4 changes: 2 additions & 2 deletions src/test/ui/self/arbitrary-self-types-not-object-safe.stderr
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
error[E0038]: the trait `Foo` cannot be made into an object
--> $DIR/arbitrary-self-types-not-object-safe.rs:31:32
--> $DIR/arbitrary-self-types-not-object-safe.rs:29:32
|
LL | fn foo(self: &Rc<Self>) -> usize;
| --- method `foo`'s `self` parameter cannot be dispatched on
Expand All @@ -8,7 +8,7 @@ LL | let x = Rc::new(5usize) as Rc<dyn Foo>;
| ^^^^^^^^^^^ the trait `Foo` cannot be made into an object

error[E0038]: the trait `Foo` cannot be made into an object
--> $DIR/arbitrary-self-types-not-object-safe.rs:31:13
--> $DIR/arbitrary-self-types-not-object-safe.rs:29:13
|
LL | fn foo(self: &Rc<Self>) -> usize;
| --- method `foo`'s `self` parameter cannot be dispatched on
Expand Down
36 changes: 36 additions & 0 deletions src/test/ui/self/arbitrary_self_types_nested.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// run-pass

use {
std::{
rc::Rc,
sync::Arc,
},
};

#[derive(Default)]
struct Ty;

trait Trait {
fn receive_trait(self: &Arc<Rc<Box<Self>>>) -> u32;
}

const TRAIT_MAGIC: u32 = 42;
const INHERENT_MAGIC: u32 = 1995;

impl Trait for Ty {
fn receive_trait(self: &Arc<Rc<Box<Self>>>) -> u32 {
TRAIT_MAGIC
}
}

impl Ty {
fn receive_inherent(self: &Arc<Rc<Box<Self>>>) -> u32 {
INHERENT_MAGIC
}
}

fn main() {
let ty = <Arc<Rc<Box<Ty>>>>::default();
assert_eq!(TRAIT_MAGIC, ty.receive_trait());
assert_eq!(INHERENT_MAGIC, ty.receive_inherent());
}
1 change: 0 additions & 1 deletion src/test/ui/self/arbitrary_self_types_struct.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
// run-pass
#![feature(arbitrary_self_types)]

use std::rc::Rc;

Expand Down
1 change: 0 additions & 1 deletion src/test/ui/self/arbitrary_self_types_trait.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
// run-pass
#![feature(arbitrary_self_types)]

use std::rc::Rc;

Expand Down
1 change: 0 additions & 1 deletion src/test/ui/self/arbitrary_self_types_unsized_struct.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
// run-pass
#![feature(arbitrary_self_types)]

use std::rc::Rc;

Expand Down
1 change: 0 additions & 1 deletion src/test/ui/self/elision/alias-async.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
// check-pass
// edition:2018

#![feature(arbitrary_self_types)]
#![allow(non_snake_case)]

use std::rc::Rc;
Expand Down
1 change: 0 additions & 1 deletion src/test/ui/self/elision/alias.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
// check-pass

#![feature(arbitrary_self_types)]
#![allow(non_snake_case)]

use std::rc::Rc;
Expand Down
1 change: 0 additions & 1 deletion src/test/ui/self/elision/assoc-async.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
// check-pass
// edition:2018

#![feature(arbitrary_self_types)]
#![allow(non_snake_case)]

use std::rc::Rc;
Expand Down
1 change: 0 additions & 1 deletion src/test/ui/self/elision/assoc.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
// check-pass

#![feature(arbitrary_self_types)]
#![allow(non_snake_case)]

use std::rc::Rc;
Expand Down
1 change: 0 additions & 1 deletion src/test/ui/self/elision/lt-alias-async.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
// check-pass
// edition:2018

#![feature(arbitrary_self_types)]
#![allow(non_snake_case)]

use std::rc::Rc;
Expand Down
1 change: 0 additions & 1 deletion src/test/ui/self/elision/lt-alias.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
// check-pass

#![feature(arbitrary_self_types)]
#![allow(non_snake_case)]

use std::rc::Rc;
Expand Down
1 change: 0 additions & 1 deletion src/test/ui/self/elision/lt-assoc-async.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
// check-pass
// edition:2018

#![feature(arbitrary_self_types)]
#![allow(non_snake_case)]

use std::rc::Rc;
Expand Down
1 change: 0 additions & 1 deletion src/test/ui/self/elision/lt-assoc.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
// check-pass

#![feature(arbitrary_self_types)]
#![allow(non_snake_case)]

use std::rc::Rc;
Expand Down
24 changes: 12 additions & 12 deletions src/test/ui/self/elision/lt-ref-self-async.nll.stderr
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
--> $DIR/lt-ref-self-async.rs:13:42
--> $DIR/lt-ref-self-async.rs:12:42
|
LL | async fn ref_self(&self, f: &u32) -> &u32 {
| ^^^^
|
= note: hidden type `impl std::future::Future` captures lifetime '_#23r

error: lifetime may not live long enough
--> $DIR/lt-ref-self-async.rs:14:9
--> $DIR/lt-ref-self-async.rs:13:9
|
LL | async fn ref_self(&self, f: &u32) -> &u32 {
| -
Expand All @@ -18,15 +18,15 @@ LL | f
| ^ function was supposed to return data with lifetime `'_` but it is returning data with lifetime `'_`

error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
--> $DIR/lt-ref-self-async.rs:19:48
--> $DIR/lt-ref-self-async.rs:18:48
|
LL | async fn ref_Self(self: &Self, f: &u32) -> &u32 {
| ^^^^
|
= note: hidden type `impl std::future::Future` captures lifetime '_#23r

error: lifetime may not live long enough
--> $DIR/lt-ref-self-async.rs:20:9
--> $DIR/lt-ref-self-async.rs:19:9
|
LL | async fn ref_Self(self: &Self, f: &u32) -> &u32 {
| -
Expand All @@ -37,15 +37,15 @@ LL | f
| ^ function was supposed to return data with lifetime `'_` but it is returning data with lifetime `'_`

error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
--> $DIR/lt-ref-self-async.rs:23:57
--> $DIR/lt-ref-self-async.rs:22:57
|
LL | async fn box_ref_Self(self: Box<&Self>, f: &u32) -> &u32 {
| ^^^^
|
= note: hidden type `impl std::future::Future` captures lifetime '_#23r

error: lifetime may not live long enough
--> $DIR/lt-ref-self-async.rs:24:9
--> $DIR/lt-ref-self-async.rs:23:9
|
LL | async fn box_ref_Self(self: Box<&Self>, f: &u32) -> &u32 {
| -
Expand All @@ -56,15 +56,15 @@ LL | f
| ^ function was supposed to return data with lifetime `'_` but it is returning data with lifetime `'_`

error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
--> $DIR/lt-ref-self-async.rs:27:57
--> $DIR/lt-ref-self-async.rs:26:57
|
LL | async fn pin_ref_Self(self: Pin<&Self>, f: &u32) -> &u32 {
| ^^^^
|
= note: hidden type `impl std::future::Future` captures lifetime '_#23r

error: lifetime may not live long enough
--> $DIR/lt-ref-self-async.rs:28:9
--> $DIR/lt-ref-self-async.rs:27:9
|
LL | async fn pin_ref_Self(self: Pin<&Self>, f: &u32) -> &u32 {
| -
Expand All @@ -75,15 +75,15 @@ LL | f
| ^ function was supposed to return data with lifetime `'_` but it is returning data with lifetime `'_`

error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
--> $DIR/lt-ref-self-async.rs:31:66
--> $DIR/lt-ref-self-async.rs:30:66
|
LL | async fn box_box_ref_Self(self: Box<Box<&Self>>, f: &u32) -> &u32 {
| ^^^^
|
= note: hidden type `impl std::future::Future` captures lifetime '_#23r

error: lifetime may not live long enough
--> $DIR/lt-ref-self-async.rs:32:9
--> $DIR/lt-ref-self-async.rs:31:9
|
LL | async fn box_box_ref_Self(self: Box<Box<&Self>>, f: &u32) -> &u32 {
| -
Expand All @@ -94,15 +94,15 @@ LL | f
| ^ function was supposed to return data with lifetime `'_` but it is returning data with lifetime `'_`

error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
--> $DIR/lt-ref-self-async.rs:35:62
--> $DIR/lt-ref-self-async.rs:34:62
|
LL | async fn box_pin_Self(self: Box<Pin<&Self>>, f: &u32) -> &u32 {
| ^^^^
|
= note: hidden type `impl std::future::Future` captures lifetime '_#23r

error: lifetime may not live long enough
--> $DIR/lt-ref-self-async.rs:36:9
--> $DIR/lt-ref-self-async.rs:35:9
|
LL | async fn box_pin_Self(self: Box<Pin<&Self>>, f: &u32) -> &u32 {
| -
Expand Down
1 change: 0 additions & 1 deletion src/test/ui/self/elision/lt-ref-self-async.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
// edition:2018

#![feature(arbitrary_self_types)]
#![allow(non_snake_case)]

use std::pin::Pin;
Expand Down
Loading

0 comments on commit 2083e2a

Please sign in to comment.