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

Stabilize nested self receivers in 1.41.0 #64325

Merged
merged 1 commit into from Nov 28, 2019
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
79 changes: 48 additions & 31 deletions src/librustc_typeck/check/wfcheck.rs
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,
Centril marked this conversation as resolved.
Show resolved Hide resolved
);

// 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
cramertj marked this conversation as resolved.
Show resolved Hide resolved
}

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,
Centril marked this conversation as resolved.
Show resolved Hide resolved
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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -0,0 +1,36 @@
// run-pass
cramertj marked this conversation as resolved.
Show resolved Hide resolved

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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -1,6 +1,5 @@
// edition:2018

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

use std::pin::Pin;
Expand Down