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

Address review comments from #98259 #98365

Merged
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
16 changes: 15 additions & 1 deletion compiler/rustc_middle/src/ty/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ use std::mem;
use std::ops::{Bound, Deref};
use std::sync::Arc;

use super::RvalueScopes;
use super::{ImplPolarity, RvalueScopes};

pub trait OnDiskCache<'tcx>: rustc_data_structures::sync::Sync {
/// Creates a new `OnDiskCache` instance from the serialized data in `data`.
Expand Down Expand Up @@ -2224,6 +2224,20 @@ impl<'tcx> TyCtxt<'tcx> {
})
}

/// Given a `ty`, return whether it's an `impl Future<...>`.
pub fn ty_is_opaque_future(self, ty: Ty<'_>) -> bool {
Comment on lines +2227 to +2228
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm pretty sure this can be used in multiple places! I recall seeing similar needs elsewhere.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, this is the only other place I see looking at opaque Future types:

pub fn get_impl_future_output_ty(&self, ty: Ty<'tcx>) -> Option<Binder<'tcx, Ty<'tcx>>> {

that needs the Output type from the future - maybe I shouldn't have added this method and I should just use get_impl_future_output_ty().is_some() instead?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, that'd be a good idea. Could you make a small PR for it at some point?

let ty::Opaque(def_id, _) = ty.kind() else { return false };
let future_trait = self.lang_items().future_trait().unwrap();

self.explicit_item_bounds(def_id).iter().any(|(predicate, _)| {
let ty::PredicateKind::Trait(trait_predicate) = predicate.kind().skip_binder() else {
return false;
};
trait_predicate.trait_ref.def_id == future_trait
&& trait_predicate.polarity == ImplPolarity::Positive
})
}

/// Computes the def-ids of the transitive supertraits of `trait_def_id`. This (intentionally)
/// does not compute the full elaborated super-predicates but just the set of def-ids. It is used
/// to identify which traits may define a given associated type to help avoid cycle errors.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2397,24 +2397,87 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
{
let parent_trait_ref =
self.resolve_vars_if_possible(data.parent_trait_pred);
let ty = parent_trait_ref.skip_binder().self_ty();
matches!(ty.kind(), ty::Generator(..))
|| matches!(ty.kind(), ty::Closure(..))
let nested_ty = parent_trait_ref.skip_binder().self_ty();
matches!(nested_ty.kind(), ty::Generator(..))
|| matches!(nested_ty.kind(), ty::Closure(..))
} else {
false
}
};

let from_generator = tcx.lang_items().from_generator_fn().unwrap();

// Don't print the tuple of capture types
if !is_upvar_tys_infer_tuple {
let msg = format!("required because it appears within the type `{}`", ty);
match ty.kind() {
ty::Adt(def, _) => match self.tcx.opt_item_ident(def.did()) {
Some(ident) => err.span_note(ident.span, &msg),
None => err.note(&msg),
},
_ => err.note(&msg),
};
'print: {
if !is_upvar_tys_infer_tuple {
let msg = format!("required because it appears within the type `{}`", ty);
match ty.kind() {
ty::Adt(def, _) => {
// `gen_future` is used in all async functions; it doesn't add any additional info.
if self.tcx.is_diagnostic_item(sym::gen_future, def.did()) {
break 'print;
}
match self.tcx.opt_item_ident(def.did()) {
Some(ident) => err.span_note(ident.span, &msg),
None => err.note(&msg),
}
}
ty::Opaque(def_id, _) => {
// Avoid printing the future from `core::future::from_generator`, it's not helpful
if tcx.parent(*def_id) == from_generator {
break 'print;
}

// If the previous type is `from_generator`, this is the future generated by the body of an async function.
// Avoid printing it twice (it was already printed in the `ty::Generator` arm below).
let is_future = tcx.ty_is_opaque_future(ty);
debug!(
?obligated_types,
?is_future,
"note_obligation_cause_code: check for async fn"
);
if is_future
&& obligated_types.last().map_or(false, |ty| match ty.kind() {
ty::Opaque(last_def_id, _) => {
tcx.parent(*last_def_id) == from_generator
}
_ => false,
})
{
break 'print;
}
err.span_note(self.tcx.def_span(def_id), &msg)
}
ty::GeneratorWitness(bound_tys) => {
use std::fmt::Write;

// FIXME: this is kind of an unusual format for rustc, can we make it more clear?
// Maybe we should just remove this note altogether?
// FIXME: only print types which don't meet the trait requirement
let mut msg =
"required because it captures the following types: ".to_owned();
for ty in bound_tys.skip_binder() {
write!(msg, "`{}`, ", ty).unwrap();
}
err.note(msg.trim_end_matches(", "))
}
ty::Generator(def_id, _, _) => {
let sp = self.tcx.def_span(def_id);

// Special-case this to say "async block" instead of `[static generator]`.
let kind = tcx.generator_kind(def_id).unwrap();
err.span_note(
sp,
&format!("required because it's used within this {}", kind),
)
}
ty::Closure(def_id, _) => err.span_note(
self.tcx.def_span(def_id),
&format!("required because it's used within this closure"),
),
_ => err.note(&msg),
};
}
}

obligated_types.push(ty);
Expand Down
30 changes: 21 additions & 9 deletions src/test/ui/async-await/issue-68112.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -42,15 +42,27 @@ LL | require_send(send_fut);
|
= help: the trait `Sync` is not implemented for `RefCell<i32>`
= note: required because of the requirements on the impl of `Send` for `Arc<RefCell<i32>>`
= note: required because it appears within the type `[static generator@$DIR/issue-68112.rs:47:31: 47:36]`
= note: required because it appears within the type `std::future::from_generator::GenFuture<[static generator@$DIR/issue-68112.rs:47:31: 47:36]>`
= note: required because it appears within the type `impl Future<Output = Arc<RefCell<i32>>>`
= note: required because it appears within the type `impl Future<Output = Arc<RefCell<i32>>>`
= note: required because it appears within the type `impl Future<Output = Arc<RefCell<i32>>>`
= note: required because it appears within the type `{ResumeTy, impl Future<Output = Arc<RefCell<i32>>>, (), i32, Ready<i32>}`
= note: required because it appears within the type `[static generator@$DIR/issue-68112.rs:55:26: 59:6]`
= note: required because it appears within the type `std::future::from_generator::GenFuture<[static generator@$DIR/issue-68112.rs:55:26: 59:6]>`
= note: required because it appears within the type `impl Future<Output = ()>`
note: required because it's used within this `async fn` body
--> $DIR/issue-68112.rs:47:31
|
LL | async fn ready2<T>(t: T) -> T { t }
| ^^^^^
note: required because it appears within the type `impl Future<Output = Arc<RefCell<i32>>>`
--> $DIR/issue-68112.rs:48:31
|
LL | fn make_non_send_future2() -> impl Future<Output = Arc<RefCell<i32>>> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: required because it captures the following types: `ResumeTy`, `impl Future<Output = Arc<RefCell<i32>>>`, `()`, `i32`, `Ready<i32>`
note: required because it's used within this `async` block
--> $DIR/issue-68112.rs:55:26
|
LL | let send_fut = async {
| __________________________^
LL | | let non_send_fut = make_non_send_future2();
LL | | let _ = non_send_fut.await;
LL | | ready(0).await;
LL | | };
| |_____^
note: required by a bound in `require_send`
--> $DIR/issue-68112.rs:11:25
|
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
error[E0277]: `Sender<i32>` cannot be shared between threads safely
--> $DIR/issue-70935-complex-spans.rs:13:45
|
LL | fn foo(tx: std::sync::mpsc::Sender<i32>) -> impl Future + Send {
| ^^^^^^^^^^^^^^^^^^ `Sender<i32>` cannot be shared between threads safely
|
= help: the trait `Sync` is not implemented for `Sender<i32>`
= note: required because of the requirements on the impl of `Send` for `&Sender<i32>`
note: required because it's used within this closure
--> $DIR/issue-70935-complex-spans.rs:25:13
|
LL | baz(|| async{
| _____________^
LL | | foo(tx.clone());
LL | | }).await;
| |_________^
note: required because it's used within this `async fn` body
--> $DIR/issue-70935-complex-spans.rs:9:67
|
LL | async fn baz<T>(_c: impl FnMut() -> T) where T: Future<Output=()> {
| ___________________________________________________________________^
LL | |
LL | | }
| |_^
= note: required because it captures the following types: `ResumeTy`, `impl Future<Output = ()>`, `()`
note: required because it's used within this `async` block
--> $DIR/issue-70935-complex-spans.rs:23:16
|
LL | async move {
| ________________^
LL | |
LL | | baz(|| async{
LL | | foo(tx.clone());
LL | | }).await;
LL | | }
| |_____^

error: aborting due to previous error

For more information about this error, try `rustc --explain E0277`.
Original file line number Diff line number Diff line change
@@ -1,22 +1,22 @@
error: future cannot be sent between threads safely
--> $DIR/issue-70935-complex-spans.rs:10:45
--> $DIR/issue-70935-complex-spans.rs:13:45
|
LL | fn foo(tx: std::sync::mpsc::Sender<i32>) -> impl Future + Send {
| ^^^^^^^^^^^^^^^^^^ future created by async block is not `Send`
|
= help: the trait `Sync` is not implemented for `Sender<i32>`
note: future is not `Send` as this value is used across an await
--> $DIR/issue-70935-complex-spans.rs:15:11
--> $DIR/issue-70935-complex-spans.rs:27:11
|
LL | baz(|| async{
| _____________-
LL | | foo(tx.clone());
LL | | }).await;
| | - ^^^^^^ await occurs here, with the value maybe used later
| |_________|
| has type `[closure@$DIR/issue-70935-complex-spans.rs:13:13: 15:10]` which is not `Send`
| has type `[closure@$DIR/issue-70935-complex-spans.rs:25:13: 27:10]` which is not `Send`
note: the value is later dropped here
--> $DIR/issue-70935-complex-spans.rs:15:17
--> $DIR/issue-70935-complex-spans.rs:27:17
|
LL | }).await;
| ^
Expand Down
16 changes: 14 additions & 2 deletions src/test/ui/async-await/issue-70935-complex-spans.rs
Original file line number Diff line number Diff line change
@@ -1,16 +1,28 @@
// edition:2018
// revisions: normal drop_tracking
// [drop_tracking]compile-flags:-Zdrop-tracking
// #70935: Check if we do not emit snippet
// with newlines which lead complex diagnostics.

use std::future::Future;

async fn baz<T>(_c: impl FnMut() -> T) where T: Future<Output=()> {
//[drop_tracking]~^ within this `async fn` body
}

fn foo(tx: std::sync::mpsc::Sender<i32>) -> impl Future + Send {
//~^ ERROR: future cannot be sent between threads safely
//[normal]~^ ERROR: future cannot be sent between threads safely
//[drop_tracking]~^^ ERROR: `Sender<i32>` cannot be shared
//[drop_tracking]~| NOTE: cannot be shared
//[drop_tracking]~| NOTE: requirements on the impl of `Send`
//[drop_tracking]~| NOTE: captures the following types
//[drop_tracking]~| NOTE: in this expansion
//[drop_tracking]~| NOTE: in this expansion
//[drop_tracking]~| NOTE: in this expansion
//[drop_tracking]~| NOTE: in this expansion
async move {
baz(|| async{
//[drop_tracking]~^ within this `async` block
baz(|| async{ //[drop_tracking]~ NOTE: used within this closure
foo(tx.clone());
}).await;
}
Expand Down
8 changes: 8 additions & 0 deletions src/test/ui/async-await/partial-drop-partial-reinit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,15 @@
fn main() {
gimme_send(foo());
//~^ ERROR cannot be sent between threads safely
//~| NOTE cannot be sent
//~| NOTE bound introduced by
//~| NOTE appears within the type
//~| NOTE captures the following types
}

fn gimme_send<T: Send>(t: T) {
//~^ NOTE required by this bound
//~| NOTE required by a bound
drop(t);
}

Expand All @@ -20,6 +26,8 @@ impl Drop for NotSend {
impl !Send for NotSend {}

async fn foo() {
//~^ NOTE used within this `async fn` body
//~| NOTE within this `impl Future
let mut x = (NotSend {},);
drop(x.0);
x.0 = NotSend {};
Expand Down
20 changes: 14 additions & 6 deletions src/test/ui/async-await/partial-drop-partial-reinit.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,21 @@ LL | async fn foo() {
|
= help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `NotSend`
= note: required because it appears within the type `(NotSend,)`
= note: required because it appears within the type `{ResumeTy, (NotSend,), impl Future<Output = ()>, ()}`
= note: required because it appears within the type `[static generator@$DIR/partial-drop-partial-reinit.rs:22:16: 27:2]`
= note: required because it appears within the type `std::future::from_generator::GenFuture<[static generator@$DIR/partial-drop-partial-reinit.rs:22:16: 27:2]>`
= note: required because it appears within the type `impl Future<Output = ()>`
= note: required because it appears within the type `impl Future<Output = ()>`
= note: required because it captures the following types: `ResumeTy`, `(NotSend,)`, `impl Future<Output = ()>`, `()`
note: required because it's used within this `async fn` body
--> $DIR/partial-drop-partial-reinit.rs:28:16
|
LL | async fn foo() {
| ________________^
LL | |
LL | |
LL | | let mut x = (NotSend {},);
... |
LL | | bar().await;
LL | | }
| |_^
note: required by a bound in `gimme_send`
--> $DIR/partial-drop-partial-reinit.rs:10:18
--> $DIR/partial-drop-partial-reinit.rs:14:18
|
LL | fn gimme_send<T: Send>(t: T) {
| ^^^^ required by this bound in `gimme_send`
Expand Down
16 changes: 14 additions & 2 deletions src/test/ui/closures/closure-move-sync.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,15 @@ LL | let t = thread::spawn(|| {
|
= help: the trait `Sync` is not implemented for `std::sync::mpsc::Receiver<()>`
= note: required because of the requirements on the impl of `Send` for `&std::sync::mpsc::Receiver<()>`
= note: required because it appears within the type `[closure@$DIR/closure-move-sync.rs:6:27: 9:6]`
note: required because it's used within this closure
--> $DIR/closure-move-sync.rs:6:27
|
LL | let t = thread::spawn(|| {
| ___________________________^
LL | | recv.recv().unwrap();
LL | |
LL | | });
| |_____^
note: required by a bound in `spawn`
--> $SRC_DIR/std/src/thread/mod.rs:LL:COL
|
Expand All @@ -21,7 +29,11 @@ LL | thread::spawn(|| tx.send(()).unwrap());
|
= help: the trait `Sync` is not implemented for `Sender<()>`
= note: required because of the requirements on the impl of `Send` for `&Sender<()>`
= note: required because it appears within the type `[closure@$DIR/closure-move-sync.rs:18:19: 18:42]`
note: required because it's used within this closure
--> $DIR/closure-move-sync.rs:18:19
|
LL | thread::spawn(|| tx.send(()).unwrap());
| ^^^^^^^^^^^^^^^^^^^^^^^
note: required by a bound in `spawn`
--> $SRC_DIR/std/src/thread/mod.rs:LL:COL
|
Expand Down
Loading