Skip to content

Commit c571b2a

Browse files
authored
Rollup merge of rust-lang#104593 - compiler-errors:rpitit-object-safety-spans, r=fee1-dead
Improve spans for RPITIT object-safety errors No reason why we can't point at the `impl Trait` that causes the object-safety violation. Also [drive-by: Add is_async fn to hir::IsAsync](rust-lang@c4165f3), which touches clippy too.
2 parents c916a8d + 9a9d0f4 commit c571b2a

File tree

11 files changed

+86
-27
lines changed

11 files changed

+86
-27
lines changed

compiler/rustc_const_eval/src/transform/check_consts/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ impl<'mir, 'tcx> ConstCx<'mir, 'tcx> {
6262
}
6363

6464
fn is_async(&self) -> bool {
65-
self.tcx.asyncness(self.def_id()) == hir::IsAsync::Async
65+
self.tcx.asyncness(self.def_id()).is_async()
6666
}
6767
}
6868

compiler/rustc_hir/src/hir.rs

+6
Original file line numberDiff line numberDiff line change
@@ -2720,6 +2720,12 @@ pub enum IsAsync {
27202720
NotAsync,
27212721
}
27222722

2723+
impl IsAsync {
2724+
pub fn is_async(self) -> bool {
2725+
self == IsAsync::Async
2726+
}
2727+
}
2728+
27232729
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, Encodable, Decodable, HashStable_Generic)]
27242730
pub enum Defaultness {
27252731
Default { has_value: bool },

compiler/rustc_hir_analysis/src/check/compare_method.rs

+1-3
Original file line numberDiff line numberDiff line change
@@ -684,9 +684,7 @@ fn report_trait_method_mismatch<'tcx>(
684684
// Suggestion to change output type. We do not suggest in `async` functions
685685
// to avoid complex logic or incorrect output.
686686
match tcx.hir().expect_impl_item(impl_m.def_id.expect_local()).kind {
687-
ImplItemKind::Fn(ref sig, _)
688-
if sig.header.asyncness == hir::IsAsync::NotAsync =>
689-
{
687+
ImplItemKind::Fn(ref sig, _) if !sig.header.asyncness.is_async() => {
690688
let msg = "change the output type to match the trait";
691689
let ap = Applicability::MachineApplicable;
692690
match sig.decl.output {

compiler/rustc_middle/src/traits/mod.rs

+8-2
Original file line numberDiff line numberDiff line change
@@ -924,10 +924,13 @@ impl ObjectSafetyViolation {
924924
}
925925
ObjectSafetyViolation::Method(
926926
name,
927-
MethodViolationCode::ReferencesImplTraitInTrait,
927+
MethodViolationCode::ReferencesImplTraitInTrait(_),
928928
_,
929929
) => format!("method `{}` references an `impl Trait` type in its return type", name)
930930
.into(),
931+
ObjectSafetyViolation::Method(name, MethodViolationCode::AsyncFn, _) => {
932+
format!("method `{}` is `async`", name).into()
933+
}
931934
ObjectSafetyViolation::Method(
932935
name,
933936
MethodViolationCode::WhereClauseReferencesSelf,
@@ -1035,7 +1038,10 @@ pub enum MethodViolationCode {
10351038
ReferencesSelfOutput,
10361039

10371040
/// e.g., `fn foo(&self) -> impl Sized`
1038-
ReferencesImplTraitInTrait,
1041+
ReferencesImplTraitInTrait(Span),
1042+
1043+
/// e.g., `async fn foo(&self)`
1044+
AsyncFn,
10391045

10401046
/// e.g., `fn foo(&self) where Self: Clone`
10411047
WhereClauseReferencesSelf,

compiler/rustc_trait_selection/src/traits/object_safety.rs

+15-6
Original file line numberDiff line numberDiff line change
@@ -375,6 +375,7 @@ fn object_safety_violation_for_method(
375375
let span = match (&v, node) {
376376
(MethodViolationCode::ReferencesSelfInput(Some(span)), _) => *span,
377377
(MethodViolationCode::UndispatchableReceiver(Some(span)), _) => *span,
378+
(MethodViolationCode::ReferencesImplTraitInTrait(span), _) => *span,
378379
(MethodViolationCode::ReferencesSelfOutput, Some(node)) => {
379380
node.fn_decl().map_or(method.ident(tcx).span, |decl| decl.output.span())
380381
}
@@ -437,8 +438,8 @@ fn virtual_call_violation_for_method<'tcx>(
437438
if contains_illegal_self_type_reference(tcx, trait_def_id, sig.output()) {
438439
return Some(MethodViolationCode::ReferencesSelfOutput);
439440
}
440-
if contains_illegal_impl_trait_in_trait(tcx, sig.output()) {
441-
return Some(MethodViolationCode::ReferencesImplTraitInTrait);
441+
if let Some(code) = contains_illegal_impl_trait_in_trait(tcx, method.def_id, sig.output()) {
442+
return Some(code);
442443
}
443444

444445
// We can't monomorphize things like `fn foo<A>(...)`.
@@ -864,16 +865,24 @@ fn contains_illegal_self_type_reference<'tcx, T: TypeVisitable<'tcx>>(
864865

865866
pub fn contains_illegal_impl_trait_in_trait<'tcx>(
866867
tcx: TyCtxt<'tcx>,
868+
fn_def_id: DefId,
867869
ty: ty::Binder<'tcx, Ty<'tcx>>,
868-
) -> bool {
870+
) -> Option<MethodViolationCode> {
871+
// This would be caught below, but rendering the error as a separate
872+
// `async-specific` message is better.
873+
if tcx.asyncness(fn_def_id).is_async() {
874+
return Some(MethodViolationCode::AsyncFn);
875+
}
876+
869877
// FIXME(RPITIT): Perhaps we should use a visitor here?
870-
ty.skip_binder().walk().any(|arg| {
878+
ty.skip_binder().walk().find_map(|arg| {
871879
if let ty::GenericArgKind::Type(ty) = arg.unpack()
872880
&& let ty::Projection(proj) = ty.kind()
881+
&& tcx.def_kind(proj.item_def_id) == DefKind::ImplTraitPlaceholder
873882
{
874-
tcx.def_kind(proj.item_def_id) == DefKind::ImplTraitPlaceholder
883+
Some(MethodViolationCode::ReferencesImplTraitInTrait(tcx.def_span(proj.item_def_id)))
875884
} else {
876-
false
885+
None
877886
}
878887
})
879888
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// edition:2021
2+
3+
#![feature(async_fn_in_trait)]
4+
//~^ WARN the feature `async_fn_in_trait` is incomplete and may not be safe to use and/or cause compiler crashes
5+
6+
trait Foo {
7+
async fn foo(&self);
8+
}
9+
10+
fn main() {
11+
let x: &dyn Foo = todo!();
12+
//~^ ERROR the trait `Foo` cannot be made into an object
13+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
warning: the feature `async_fn_in_trait` is incomplete and may not be safe to use and/or cause compiler crashes
2+
--> $DIR/object-safety.rs:3:12
3+
|
4+
LL | #![feature(async_fn_in_trait)]
5+
| ^^^^^^^^^^^^^^^^^
6+
|
7+
= note: see issue #91611 <https://github.com/rust-lang/rust/issues/91611> for more information
8+
= note: `#[warn(incomplete_features)]` on by default
9+
10+
error[E0038]: the trait `Foo` cannot be made into an object
11+
--> $DIR/object-safety.rs:11:12
12+
|
13+
LL | let x: &dyn Foo = todo!();
14+
| ^^^^^^^^ `Foo` cannot be made into an object
15+
|
16+
note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
17+
--> $DIR/object-safety.rs:7:14
18+
|
19+
LL | trait Foo {
20+
| --- this trait cannot be made into an object...
21+
LL | async fn foo(&self);
22+
| ^^^ ...because method `foo` is `async`
23+
= help: consider moving `foo` to another trait
24+
25+
error: aborting due to previous error; 1 warning emitted
26+
27+
For more information about this error, try `rustc --explain E0038`.

src/test/ui/impl-trait/in-trait/object-safety.stderr

+6-6
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,12 @@ LL | let i = Box::new(42_u32) as Box<dyn Foo>;
55
| ^^^^^^^^^^^^ `Foo` cannot be made into an object
66
|
77
note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
8-
--> $DIR/object-safety.rs:7:8
8+
--> $DIR/object-safety.rs:7:22
99
|
1010
LL | trait Foo {
1111
| --- this trait cannot be made into an object...
1212
LL | fn baz(&self) -> impl Debug;
13-
| ^^^ ...because method `baz` references an `impl Trait` type in its return type
13+
| ^^^^^^^^^^ ...because method `baz` references an `impl Trait` type in its return type
1414
= help: consider moving `baz` to another trait
1515

1616
error[E0038]: the trait `Foo` cannot be made into an object
@@ -20,12 +20,12 @@ LL | let s = i.baz();
2020
| ^^^^^^^ `Foo` cannot be made into an object
2121
|
2222
note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
23-
--> $DIR/object-safety.rs:7:8
23+
--> $DIR/object-safety.rs:7:22
2424
|
2525
LL | trait Foo {
2626
| --- this trait cannot be made into an object...
2727
LL | fn baz(&self) -> impl Debug;
28-
| ^^^ ...because method `baz` references an `impl Trait` type in its return type
28+
| ^^^^^^^^^^ ...because method `baz` references an `impl Trait` type in its return type
2929
= help: consider moving `baz` to another trait
3030

3131
error[E0038]: the trait `Foo` cannot be made into an object
@@ -35,12 +35,12 @@ LL | let i = Box::new(42_u32) as Box<dyn Foo>;
3535
| ^^^^^^^^^^^^^^^^ `Foo` cannot be made into an object
3636
|
3737
note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
38-
--> $DIR/object-safety.rs:7:8
38+
--> $DIR/object-safety.rs:7:22
3939
|
4040
LL | trait Foo {
4141
| --- this trait cannot be made into an object...
4242
LL | fn baz(&self) -> impl Debug;
43-
| ^^^ ...because method `baz` references an `impl Trait` type in its return type
43+
| ^^^^^^^^^^ ...because method `baz` references an `impl Trait` type in its return type
4444
= help: consider moving `baz` to another trait
4545
= note: required for `Box<u32>` to implement `CoerceUnsized<Box<dyn Foo>>`
4646
= note: required by cast to type `Box<dyn Foo>`

src/tools/clippy/clippy_lints/src/manual_async_fn.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use rustc_errors::Applicability;
66
use rustc_hir::intravisit::FnKind;
77
use rustc_hir::{
88
AsyncGeneratorKind, Block, Body, Closure, Expr, ExprKind, FnDecl, FnRetTy, GeneratorKind, GenericArg, GenericBound,
9-
HirId, IsAsync, ItemKind, LifetimeName, Term, TraitRef, Ty, TyKind, TypeBindingKind,
9+
HirId, ItemKind, LifetimeName, Term, TraitRef, Ty, TyKind, TypeBindingKind,
1010
};
1111
use rustc_lint::{LateContext, LateLintPass};
1212
use rustc_session::{declare_lint_pass, declare_tool_lint};
@@ -49,7 +49,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualAsyncFn {
4949
) {
5050
if_chain! {
5151
if let Some(header) = kind.header();
52-
if header.asyncness == IsAsync::NotAsync;
52+
if !header.asyncness.is_async();
5353
// Check that this function returns `impl Future`
5454
if let FnRetTy::Return(ret_ty) = decl.output;
5555
if let Some((trait_ref, output_lifetimes)) = future_trait_ref(cx, ret_ty);

src/tools/clippy/clippy_lints/src/unused_async.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use clippy_utils::diagnostics::span_lint_and_help;
22
use rustc_hir::intravisit::{walk_expr, walk_fn, FnKind, Visitor};
3-
use rustc_hir::{Body, Expr, ExprKind, FnDecl, HirId, IsAsync, YieldSource};
3+
use rustc_hir::{Body, Expr, ExprKind, FnDecl, HirId, YieldSource};
44
use rustc_lint::{LateContext, LateLintPass};
55
use rustc_middle::hir::nested_filter;
66
use rustc_session::{declare_lint_pass, declare_tool_lint};
@@ -68,7 +68,7 @@ impl<'tcx> LateLintPass<'tcx> for UnusedAsync {
6868
span: Span,
6969
hir_id: HirId,
7070
) {
71-
if !span.from_expansion() && fn_kind.asyncness() == IsAsync::Async {
71+
if !span.from_expansion() && fn_kind.asyncness().is_async() {
7272
let mut visitor = AsyncFnVisitor { cx, found_await: false };
7373
walk_fn(&mut visitor, fn_kind, fn_decl, body.id(), hir_id);
7474
if !visitor.found_await {

src/tools/clippy/clippy_utils/src/lib.rs

+5-5
Original file line numberDiff line numberDiff line change
@@ -87,10 +87,10 @@ use rustc_hir::hir_id::{HirIdMap, HirIdSet};
8787
use rustc_hir::intravisit::{walk_expr, FnKind, Visitor};
8888
use rustc_hir::LangItem::{OptionNone, ResultErr, ResultOk};
8989
use rustc_hir::{
90-
def, Arm, ArrayLen, BindingAnnotation, Block, BlockCheckMode, Body, Closure, Constness, Destination, Expr,
91-
ExprKind, FnDecl, HirId, Impl, ImplItem, ImplItemKind, IsAsync, Item, ItemKind, LangItem, Local, MatchSource,
92-
Mutability, Node, Param, Pat, PatKind, Path, PathSegment, PrimTy, QPath, Stmt, StmtKind, TraitItem, TraitItemKind,
93-
TraitRef, TyKind, UnOp,
90+
def, Arm, ArrayLen, BindingAnnotation, Block, BlockCheckMode, Body, Closure, Constness,
91+
Destination, Expr, ExprKind, FnDecl, HirId, Impl, ImplItem, ImplItemKind, Item, ItemKind,
92+
LangItem, Local, MatchSource, Mutability, Node, Param, Pat, PatKind, Path, PathSegment, PrimTy,
93+
QPath, Stmt, StmtKind, TraitItem, TraitItemKind, TraitRef, TyKind, UnOp,
9494
};
9595
use rustc_lexer::{tokenize, TokenKind};
9696
use rustc_lint::{LateContext, Level, Lint, LintContext};
@@ -1861,7 +1861,7 @@ pub fn if_sequence<'tcx>(mut expr: &'tcx Expr<'tcx>) -> (Vec<&'tcx Expr<'tcx>>,
18611861

18621862
/// Checks if the given function kind is an async function.
18631863
pub fn is_async_fn(kind: FnKind<'_>) -> bool {
1864-
matches!(kind, FnKind::ItemFn(_, _, header) if header.asyncness == IsAsync::Async)
1864+
matches!(kind, FnKind::ItemFn(_, _, header) if header.asyncness.is_async())
18651865
}
18661866

18671867
/// Peels away all the compiler generated code surrounding the body of an async function,

0 commit comments

Comments
 (0)