Skip to content

Commit

Permalink
Rework supertrait lint once again
Browse files Browse the repository at this point in the history
  • Loading branch information
compiler-errors committed Nov 18, 2023
1 parent 6fdc303 commit 816d811
Show file tree
Hide file tree
Showing 9 changed files with 73 additions and 21 deletions.
3 changes: 2 additions & 1 deletion compiler/rustc_lint/messages.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -496,8 +496,9 @@ lint_requested_level = requested on the command line with `{$level} {$lint_name}
lint_span_use_eq_ctxt = use `.eq_ctxt()` instead of `.ctxt() == .ctxt()`
lint_supertrait_as_deref_target = `{$t}` implements `Deref` with supertrait `{$target_principal}` as target
lint_supertrait_as_deref_target = `{$self_ty}` implements `Deref<Target = dyn {$target_principal}>` which conflicts with supertrait `{$supertrait_principal}`
.label = target type is set here
.note = inference and runtime behavior may change after `#[feature(trait_upcasting)]` is enabled by default
lint_suspicious_double_ref_clone =
using `.clone()` on a double reference, which returns `{$ty}` instead of cloning the inner type
Expand Down
36 changes: 21 additions & 15 deletions compiler/rustc_lint/src/deref_into_dyn_supertrait.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,26 +62,25 @@ impl<'tcx> LateLintPass<'tcx> for DerefIntoDynSupertrait {
let tcx = cx.tcx;
// `Deref` is being implemented for `t`
if let hir::ItemKind::Impl(impl_) = item.kind
// the trait is a `Deref` implementation
&& let Some(trait_) = &impl_.of_trait
&& let t = tcx.type_of(item.owner_id).instantiate_identity()
&& let opt_did @ Some(did) = trait_.trait_def_id()
&& 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()
&& let Some(did) = trait_.trait_def_id()
&& Some(did) == tcx.lang_items().deref_trait()
// the self type is `dyn t_principal`
&& let self_ty = tcx.type_of(item.owner_id).instantiate_identity()
&& let ty::Dynamic(data, _, ty::Dyn) = self_ty.kind()
&& let Some(self_principal) = data.principal()
// `<T as Deref>::Target` is `dyn target_principal`
&& let Some(target) = cx.get_associated_type(t, did, "Target")
&& let Some(target) = cx.get_associated_type(self_ty, did, "Target")
&& let ty::Dynamic(data, _, ty::Dyn) = target.kind()
&& let Some(target_principal) = data.principal()
// `target_principal` is a supertrait of `t_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 Some(supertrait_principal) = supertraits(tcx, self_principal.with_self_ty(tcx, self_ty))
.find(|supertrait| supertrait.def_id() == target_principal.def_id())
{
let t = tcx.erase_regions(t);
// erase regions in self type for better diagnostic presentation
let (self_ty, target_principal, supertrait_principal) =
tcx.erase_regions((self_ty, target_principal, supertrait_principal));
let label = impl_
.items
.iter()
Expand All @@ -90,7 +89,14 @@ impl<'tcx> LateLintPass<'tcx> for DerefIntoDynSupertrait {
cx.emit_spanned_lint(
DEREF_INTO_DYN_SUPERTRAIT,
tcx.def_span(item.owner_id.def_id),
SupertraitAsDerefTarget { t, target_principal, label },
SupertraitAsDerefTarget {
self_ty,
supertrait_principal: supertrait_principal.map_bound(|trait_ref| {
ty::ExistentialTraitRef::erase_self_ty(tcx, trait_ref)
}),
target_principal,
label,
},
);
}
}
Expand Down
4 changes: 3 additions & 1 deletion compiler/rustc_lint/src/lints.rs
Original file line number Diff line number Diff line change
Expand Up @@ -571,8 +571,10 @@ pub struct BuiltinUnexpectedCliConfigValue {
// deref_into_dyn_supertrait.rs
#[derive(LintDiagnostic)]
#[diag(lint_supertrait_as_deref_target)]
#[note]
pub struct SupertraitAsDerefTarget<'a> {
pub t: Ty<'a>,
pub self_ty: Ty<'a>,
pub supertrait_principal: PolyExistentialTraitRef<'a>,
pub target_principal: PolyExistentialTraitRef<'a>,
#[subdiagnostic]
pub label: Option<SupertraitAsDerefTargetLabel>,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ 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
//~^ ERROR `dyn Foo<'_>` implements `Deref<Target = dyn Bar<'_>>` which conflicts with supertrait `Bar<'_>`
//~| WARN this was previously accepted by the compiler
type Target = dyn Bar<'a>;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
error: `dyn Foo<'_>` implements `Deref` with supertrait `Bar<'_>` as target
error: `dyn Foo<'_>` implements `Deref<Target = dyn Bar<'_>>` which conflicts with supertrait `Bar<'_>`
--> $DIR/migrate-lint-deny-regions.rs:8:1
|
LL | impl<'a> Deref for dyn Foo<'a> {
Expand All @@ -9,6 +9,7 @@ LL | type Target = dyn Bar<'a>;
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #89460 <https://github.com/rust-lang/rust/issues/89460>
= note: inference and runtime behavior may change after `#[feature(trait_upcasting)]` is enabled by default
note: the lint level is defined here
--> $DIR/migrate-lint-deny-regions.rs:1:9
|
Expand Down
2 changes: 1 addition & 1 deletion tests/ui/traits/trait-upcasting/migrate-lint-deny.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ trait A {}
trait B: A {}

impl<'a> Deref for dyn 'a + B {
//~^ ERROR `dyn B` implements `Deref` with supertrait `A` as target
//~^ ERROR `dyn B` implements `Deref<Target = dyn A>` which conflicts with supertrait `A`
//~| WARN this was previously accepted by the compiler but is being phased out;

type Target = dyn A;
Expand Down
3 changes: 2 additions & 1 deletion tests/ui/traits/trait-upcasting/migrate-lint-deny.stderr
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
error: `dyn B` implements `Deref` with supertrait `A` as target
error: `dyn B` implements `Deref<Target = dyn A>` which conflicts with supertrait `A`
--> $DIR/migrate-lint-deny.rs:9:1
|
LL | impl<'a> Deref for dyn 'a + B {
Expand All @@ -9,6 +9,7 @@ LL | type Target = dyn A;
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #89460 <https://github.com/rust-lang/rust/issues/89460>
= note: inference and runtime behavior may change after `#[feature(trait_upcasting)]` is enabled by default
note: the lint level is defined here
--> $DIR/migrate-lint-deny.rs:1:9
|
Expand Down
21 changes: 21 additions & 0 deletions tests/ui/traits/trait-upcasting/migrate-lint-different-substs.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#![deny(deref_into_dyn_supertrait)]

use std::ops::Deref;

trait Bar<T> {}

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

impl<'a> Deref for dyn Foo + 'a {
//~^ ERROR `dyn Foo` implements `Deref<Target = dyn Bar<u32>>` which conflicts with supertrait `Bar<i32>`
//~| WARN this was previously accepted by the compiler
type Target = dyn Bar<u32> + 'a;

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

fn main() {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
error: `dyn Foo` implements `Deref<Target = dyn Bar<u32>>` which conflicts with supertrait `Bar<i32>`
--> $DIR/migrate-lint-different-substs.rs:11:1
|
LL | impl<'a> Deref for dyn Foo + 'a {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
...
LL | type Target = dyn Bar<u32> + '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!
= note: for more information, see issue #89460 <https://github.com/rust-lang/rust/issues/89460>
= note: inference and runtime behavior may change after `#[feature(trait_upcasting)]` is enabled by default
note: the lint level is defined here
--> $DIR/migrate-lint-different-substs.rs:1:9
|
LL | #![deny(deref_into_dyn_supertrait)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^

error: aborting due to previous error

0 comments on commit 816d811

Please sign in to comment.