Skip to content

Commit add423b

Browse files
authored
Rollup merge of rust-lang#118146 - compiler-errors:deref-into-dyn-regions, r=lcnr
Rework supertrait lint once again I accidentally pushed the wrong commits because I totally didn't check I was on the right computer when updating rust-lang#118026. Sorry, this should address all the nits in rust-lang#118026. r? lcnr
2 parents 82538b7 + 15fbcc3 commit add423b

10 files changed

+125
-25
lines changed

compiler/rustc_lint/messages.ftl

+2-1
Original file line numberDiff line numberDiff line change
@@ -491,8 +491,9 @@ lint_requested_level = requested on the command line with `{$level} {$lint_name}
491491
lint_span_use_eq_ctxt = use `.eq_ctxt()` instead of `.ctxt() == .ctxt()`
492492
493493
lint_supertrait_as_deref_target = this `Deref` implementation is covered by an implicit supertrait coercion
494+
.label = `{$self_ty}` implements `Deref<Target = dyn {$target_principal}>` which conflicts with supertrait `{$supertrait_principal}`
495+
.label2 = target type is a supertrait of `{$self_ty}`
494496
.help = consider removing this implementation or replacing it with a method instead
495-
.label = target type is a supertrait of `{$t}`
496497
497498
lint_suspicious_double_ref_clone =
498499
using `.clone()` on a double reference, which returns `{$ty}` instead of cloning the inner type

compiler/rustc_lint/src/deref_into_dyn_supertrait.rs

+25-17
Original file line numberDiff line numberDiff line change
@@ -53,35 +53,43 @@ impl<'tcx> LateLintPass<'tcx> for DerefIntoDynSupertrait {
5353
let tcx = cx.tcx;
5454
// `Deref` is being implemented for `t`
5555
if let hir::ItemKind::Impl(impl_) = item.kind
56+
// the trait is a `Deref` implementation
5657
&& let Some(trait_) = &impl_.of_trait
57-
&& let t = tcx.type_of(item.owner_id).instantiate_identity()
58-
&& let opt_did @ Some(did) = trait_.trait_def_id()
59-
&& opt_did == tcx.lang_items().deref_trait()
60-
// `t` is `dyn t_principal`
61-
&& let ty::Dynamic(data, _, ty::Dyn) = t.kind()
62-
&& let Some(t_principal) = data.principal()
58+
&& let Some(did) = trait_.trait_def_id()
59+
&& Some(did) == tcx.lang_items().deref_trait()
60+
// the self type is `dyn t_principal`
61+
&& let self_ty = tcx.type_of(item.owner_id).instantiate_identity()
62+
&& let ty::Dynamic(data, _, ty::Dyn) = self_ty.kind()
63+
&& let Some(self_principal) = data.principal()
6364
// `<T as Deref>::Target` is `dyn target_principal`
64-
&& let Some(target) = cx.get_associated_type(t, did, "Target")
65+
&& let Some(target) = cx.get_associated_type(self_ty, did, "Target")
6566
&& let ty::Dynamic(data, _, ty::Dyn) = target.kind()
6667
&& let Some(target_principal) = data.principal()
6768
// `target_principal` is a supertrait of `t_principal`
68-
&& supertraits(tcx, t_principal.with_self_ty(tcx, tcx.types.trait_object_dummy_self))
69-
.any(|sup| {
70-
tcx.erase_regions(
71-
sup.map_bound(|x| ty::ExistentialTraitRef::erase_self_ty(tcx, x)),
72-
) == tcx.erase_regions(target_principal)
73-
})
69+
&& let Some(supertrait_principal) = supertraits(tcx, self_principal.with_self_ty(tcx, self_ty))
70+
.find(|supertrait| supertrait.def_id() == target_principal.def_id())
7471
{
75-
let t = tcx.erase_regions(t);
76-
let label = impl_
72+
// erase regions in self type for better diagnostic presentation
73+
let (self_ty, target_principal, supertrait_principal) =
74+
tcx.erase_regions((self_ty, target_principal, supertrait_principal));
75+
let label2 = impl_
7776
.items
7877
.iter()
7978
.find_map(|i| (i.ident.name == sym::Target).then_some(i.span))
8079
.map(|label| SupertraitAsDerefTargetLabel { label });
80+
let span = tcx.def_span(item.owner_id.def_id);
8181
cx.emit_spanned_lint(
8282
DEREF_INTO_DYN_SUPERTRAIT,
83-
tcx.def_span(item.owner_id.def_id),
84-
SupertraitAsDerefTarget { t, label },
83+
span,
84+
SupertraitAsDerefTarget {
85+
self_ty,
86+
supertrait_principal: supertrait_principal.map_bound(|trait_ref| {
87+
ty::ExistentialTraitRef::erase_self_ty(tcx, trait_ref)
88+
}),
89+
target_principal,
90+
label: span,
91+
label2,
92+
},
8593
);
8694
}
8795
}

compiler/rustc_lint/src/lints.rs

+10-4
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,9 @@ use rustc_errors::{
1010
};
1111
use rustc_hir::def_id::DefId;
1212
use rustc_macros::{LintDiagnostic, Subdiagnostic};
13-
use rustc_middle::ty::{inhabitedness::InhabitedPredicate, Clause, Ty, TyCtxt};
13+
use rustc_middle::ty::{
14+
inhabitedness::InhabitedPredicate, Clause, PolyExistentialTraitRef, Ty, TyCtxt,
15+
};
1416
use rustc_session::parse::ParseSess;
1517
use rustc_span::{edition::Edition, sym, symbol::Ident, Span, Symbol};
1618

@@ -556,13 +558,17 @@ pub enum BuiltinSpecialModuleNameUsed {
556558
#[diag(lint_supertrait_as_deref_target)]
557559
#[help]
558560
pub struct SupertraitAsDerefTarget<'a> {
559-
pub t: Ty<'a>,
561+
pub self_ty: Ty<'a>,
562+
pub supertrait_principal: PolyExistentialTraitRef<'a>,
563+
pub target_principal: PolyExistentialTraitRef<'a>,
564+
#[label]
565+
pub label: Span,
560566
#[subdiagnostic]
561-
pub label: Option<SupertraitAsDerefTargetLabel>,
567+
pub label2: Option<SupertraitAsDerefTargetLabel>,
562568
}
563569

564570
#[derive(Subdiagnostic)]
565-
#[label(lint_label)]
571+
#[label(lint_label2)]
566572
pub struct SupertraitAsDerefTargetLabel {
567573
#[primary_span]
568574
pub label: Span,

tests/ui/traits/trait-upcasting/deref-lint-regions.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ warning: this `Deref` implementation is covered by an implicit supertrait coerci
22
--> $DIR/deref-lint-regions.rs:8:1
33
|
44
LL | impl<'a> Deref for dyn Foo<'a> {
5-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `dyn Foo<'_>` implements `Deref<Target = dyn Bar<'_>>` which conflicts with supertrait `Bar<'_>`
66
LL |
77
LL | type Target = dyn Bar<'a>;
88
| -------------------------- target type is a supertrait of `dyn Foo<'_>`

tests/ui/traits/trait-upcasting/deref-lint.rs

+1
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ trait B: A {}
88

99
impl<'a> Deref for dyn 'a + B {
1010
//~^ WARN this `Deref` implementation is covered by an implicit supertrait coercion
11+
1112
type Target = dyn A;
1213
fn deref(&self) -> &Self::Target {
1314
todo!()

tests/ui/traits/trait-upcasting/deref-lint.stderr

+2-2
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@ warning: this `Deref` implementation is covered by an implicit supertrait coerci
22
--> $DIR/deref-lint.rs:9:1
33
|
44
LL | impl<'a> Deref for dyn 'a + B {
5-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
6-
LL |
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `dyn B` implements `Deref<Target = dyn A>` which conflicts with supertrait `A`
6+
...
77
LL | type Target = dyn A;
88
| -------------------- target type is a supertrait of `dyn B`
99
|
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
#![deny(deref_into_dyn_supertrait)]
2+
use std::ops::Deref;
3+
4+
trait Bar<T> {}
5+
impl<T, U> Bar<U> for T {}
6+
7+
trait Foo: Bar<i32> {
8+
fn as_dyn_bar_u32<'a>(&self) -> &(dyn Bar<u32> + 'a);
9+
}
10+
11+
impl Foo for () {
12+
fn as_dyn_bar_u32<'a>(&self) -> &(dyn Bar<u32> + 'a) {
13+
self
14+
}
15+
}
16+
17+
impl<'a> Deref for dyn Foo + 'a {
18+
type Target = dyn Bar<u32> + 'a;
19+
20+
fn deref(&self) -> &Self::Target {
21+
self.as_dyn_bar_u32()
22+
}
23+
}
24+
25+
fn take_dyn<T>(x: &dyn Bar<T>) -> T {
26+
todo!()
27+
}
28+
29+
fn main() {
30+
let x: &dyn Foo = &();
31+
let y = take_dyn(x);
32+
let z: u32 = y;
33+
//~^ ERROR mismatched types
34+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
error[E0308]: mismatched types
2+
--> $DIR/deref-upcast-behavioral-change.rs:32:18
3+
|
4+
LL | let z: u32 = y;
5+
| --- ^ expected `u32`, found `i32`
6+
| |
7+
| expected due to this
8+
|
9+
help: you can convert an `i32` to a `u32` and panic if the converted value doesn't fit
10+
|
11+
LL | let z: u32 = y.try_into().unwrap();
12+
| ++++++++++++++++++++
13+
14+
error: aborting due to previous error
15+
16+
For more information about this error, try `rustc --explain E0308`.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// check-pass
2+
3+
use std::ops::Deref;
4+
5+
trait Bar<T> {}
6+
7+
trait Foo: Bar<i32> {
8+
fn as_dyn_bar_u32<'a>(&self) -> &(dyn Bar<u32> + 'a);
9+
}
10+
11+
impl<'a> Deref for dyn Foo + 'a {
12+
//~^ WARN this `Deref` implementation is covered by an implicit supertrait coercion
13+
type Target = dyn Bar<u32> + 'a;
14+
15+
fn deref(&self) -> &Self::Target {
16+
self.as_dyn_bar_u32()
17+
}
18+
}
19+
20+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
warning: this `Deref` implementation is covered by an implicit supertrait coercion
2+
--> $DIR/migrate-lint-different-substs.rs:11:1
3+
|
4+
LL | impl<'a> Deref for dyn Foo + 'a {
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `dyn Foo` implements `Deref<Target = dyn Bar<u32>>` which conflicts with supertrait `Bar<i32>`
6+
LL |
7+
LL | type Target = dyn Bar<u32> + 'a;
8+
| -------------------------------- target type is a supertrait of `dyn Foo`
9+
|
10+
= help: consider removing this implementation or replacing it with a method instead
11+
= note: `#[warn(deref_into_dyn_supertrait)]` on by default
12+
13+
warning: 1 warning emitted
14+

0 commit comments

Comments
 (0)