Skip to content

Commit

Permalink
Rollup merge of #118026 - compiler-errors:deref-into-dyn-regions, r=lcnr
Browse files Browse the repository at this point in the history
Don't consider regions in `deref_into_dyn_supertrait` lint

I actually wonder if we should just warn on *any* deref impl with a target type that matches a supertrait by *def-id*.

cc #89460

r? types
  • Loading branch information
matthiaskrgr committed Nov 20, 2023
2 parents 1936e2c + e6ca8e1 commit ca246d3
Show file tree
Hide file tree
Showing 7 changed files with 107 additions and 14 deletions.
18 changes: 12 additions & 6 deletions compiler/rustc_lint/src/deref_into_dyn_supertrait.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ declare_lint! {
Warn,
"`Deref` implementation usage with a supertrait trait object for output might be shadowed in the future",
@future_incompatible = FutureIncompatibleInfo {
reason: FutureIncompatibilityReason::FutureReleaseErrorDontReportInDeps,
reason: FutureIncompatibilityReason::FutureReleaseSemanticsChange,
reference: "issue #89460 <https://github.com/rust-lang/rust/issues/89460>",
};
}
Expand All @@ -59,12 +59,13 @@ declare_lint_pass!(DerefIntoDynSupertrait => [DEREF_INTO_DYN_SUPERTRAIT]);

impl<'tcx> LateLintPass<'tcx> for DerefIntoDynSupertrait {
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'tcx>) {
let tcx = cx.tcx;
// `Deref` is being implemented for `t`
if let hir::ItemKind::Impl(impl_) = item.kind
&& let Some(trait_) = &impl_.of_trait
&& let t = cx.tcx.type_of(item.owner_id).instantiate_identity()
&& let t = tcx.type_of(item.owner_id).instantiate_identity()
&& let opt_did @ Some(did) = trait_.trait_def_id()
&& opt_did == cx.tcx.lang_items().deref_trait()
&& opt_did == tcx.lang_items().deref_trait()
// `t` is `dyn t_principal`
&& let ty::Dynamic(data, _, ty::Dyn) = t.kind()
&& let Some(t_principal) = data.principal()
Expand All @@ -73,17 +74,22 @@ impl<'tcx> LateLintPass<'tcx> for DerefIntoDynSupertrait {
&& let ty::Dynamic(data, _, ty::Dyn) = target.kind()
&& let Some(target_principal) = data.principal()
// `target_principal` is a supertrait of `t_principal`
&& supertraits(cx.tcx, t_principal.with_self_ty(cx.tcx, cx.tcx.types.trait_object_dummy_self))
.any(|sup| sup.map_bound(|x| ty::ExistentialTraitRef::erase_self_ty(cx.tcx, x)) == target_principal)
&& supertraits(tcx, t_principal.with_self_ty(tcx, tcx.types.trait_object_dummy_self))
.any(|sup| {
tcx.erase_regions(
sup.map_bound(|x| ty::ExistentialTraitRef::erase_self_ty(tcx, x)),
) == tcx.erase_regions(target_principal)
})
{
let t = tcx.erase_regions(t);
let label = impl_
.items
.iter()
.find_map(|i| (i.ident.name == sym::Target).then_some(i.span))
.map(|label| SupertraitAsDerefTargetLabel { label });
cx.emit_spanned_lint(
DEREF_INTO_DYN_SUPERTRAIT,
cx.tcx.def_span(item.owner_id.def_id),
tcx.def_span(item.owner_id.def_id),
SupertraitAsDerefTarget { t, target_principal, label },
);
}
Expand Down
36 changes: 36 additions & 0 deletions tests/ui/traits/trait-upcasting/inference-behavior-change-deref.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
#![deny(deref_into_dyn_supertrait)]
#![feature(trait_upcasting)] // remove this and the test compiles

use std::ops::Deref;

trait Bar<T> {}
impl<T, U> Bar<U> for T {}

trait Foo: Bar<i32> {
fn as_dyn_bar_u32<'a>(&self) -> &(dyn Bar<u32> + 'a);
}

impl Foo for () {
fn as_dyn_bar_u32<'a>(&self) -> &(dyn Bar<u32> + 'a) {
self
}
}

impl<'a> Deref for dyn Foo + 'a {
type Target = dyn Bar<u32> + 'a;

fn deref(&self) -> &Self::Target {
self.as_dyn_bar_u32()
}
}

fn take_dyn<T>(x: &dyn Bar<T>) -> T {
todo!()
}

fn main() {
let x: &dyn Foo = &();
let y = take_dyn(x);
let z: u32 = y;
//~^ ERROR mismatched types
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
error[E0308]: mismatched types
--> $DIR/inference-behavior-change-deref.rs:34:18
|
LL | let z: u32 = y;
| --- ^ expected `u32`, found `i32`
| |
| expected due to this
|
help: you can convert an `i32` to a `u32` and panic if the converted value doesn't fit
|
LL | let z: u32 = y.try_into().unwrap();
| ++++++++++++++++++++

error: aborting due to previous error

For more information about this error, try `rustc --explain E0308`.
18 changes: 18 additions & 0 deletions tests/ui/traits/trait-upcasting/migrate-lint-deny-regions.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
#![deny(deref_into_dyn_supertrait)]

use std::ops::Deref;

trait Bar<'a> {}
trait Foo<'a>: Bar<'a> {}

impl<'a> Deref for dyn Foo<'a> {
//~^ ERROR dyn Foo<'_>` implements `Deref` with supertrait `Bar<'_>` as target
//~| WARN this will change its meaning in a future release!
type Target = dyn Bar<'a>;

fn deref(&self) -> &Self::Target {
todo!()
}
}

fn main() {}
19 changes: 19 additions & 0 deletions tests/ui/traits/trait-upcasting/migrate-lint-deny-regions.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
error: `dyn Foo<'_>` implements `Deref` with supertrait `Bar<'_>` as target
--> $DIR/migrate-lint-deny-regions.rs:8:1
|
LL | impl<'a> Deref for dyn Foo<'a> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
...
LL | type Target = dyn Bar<'a>;
| -------------------------- target type is set here
|
= warning: this will change its meaning in a future release!
= note: for more information, see issue #89460 <https://github.com/rust-lang/rust/issues/89460>
note: the lint level is defined here
--> $DIR/migrate-lint-deny-regions.rs:1:9
|
LL | #![deny(deref_into_dyn_supertrait)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^

error: aborting due to previous error

8 changes: 3 additions & 5 deletions tests/ui/traits/trait-upcasting/migrate-lint-deny.rs
Original file line number Diff line number Diff line change
@@ -1,16 +1,14 @@
#![deny(deref_into_dyn_supertrait)]

extern crate core;

use core::ops::Deref;
use std::ops::Deref;

// issue 89190
trait A {}
trait B: A {}

impl<'a> Deref for dyn 'a + B {
//~^ ERROR `(dyn B + 'a)` implements `Deref` with supertrait `A` as target
//~| WARN this was previously accepted by the compiler but is being phased out;
//~^ ERROR `dyn B` implements `Deref` with supertrait `A` as target
//~| WARN this will change its meaning in a future release!

type Target = dyn A;
fn deref(&self) -> &Self::Target {
Expand Down
6 changes: 3 additions & 3 deletions tests/ui/traits/trait-upcasting/migrate-lint-deny.stderr
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
error: `(dyn B + 'a)` implements `Deref` with supertrait `A` as target
--> $DIR/migrate-lint-deny.rs:11:1
error: `dyn B` implements `Deref` with supertrait `A` as target
--> $DIR/migrate-lint-deny.rs:9:1
|
LL | impl<'a> Deref for dyn 'a + B {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
...
LL | type Target = dyn A;
| -------------------- target type is set here
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= warning: this will change its meaning in a future release!
= note: for more information, see issue #89460 <https://github.com/rust-lang/rust/issues/89460>
note: the lint level is defined here
--> $DIR/migrate-lint-deny.rs:1:9
Expand Down

0 comments on commit ca246d3

Please sign in to comment.