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

Revert stabilization of trait_upcasting feature #120233

Merged
merged 2 commits into from
Jan 23, 2024
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
3 changes: 0 additions & 3 deletions compiler/rustc_feature/src/accepted.rs
Original file line number Diff line number Diff line change
Expand Up @@ -339,9 +339,6 @@ declare_features! (
/// Allows `#[track_caller]` to be used which provides
/// accurate caller location reporting during panic (RFC 2091).
(accepted, track_caller, "1.46.0", Some(47809)),
/// Allows dyn upcasting trait objects via supertraits.
/// Dyn upcasting is casting, e.g., `dyn Foo -> dyn Bar` where `Foo: Bar`.
(accepted, trait_upcasting, "1.76.0", Some(65991)),
/// Allows #[repr(transparent)] on univariant enums (RFC 2645).
(accepted, transparent_enums, "1.42.0", Some(60405)),
/// Allows indexing tuples.
Expand Down
3 changes: 3 additions & 0 deletions compiler/rustc_feature/src/unstable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -584,6 +584,9 @@ declare_features! (
(unstable, thread_local, "1.0.0", Some(29594)),
/// Allows defining `trait X = A + B;` alias items.
(unstable, trait_alias, "1.24.0", Some(41517)),
/// Allows dyn upcasting trait objects via supertraits.
/// Dyn upcasting is casting, e.g., `dyn Foo -> dyn Bar` where `Foo: Bar`.
(unstable, trait_upcasting, "1.56.0", Some(65991)),
/// Allows for transmuting between arrays with sizes that contain generic consts.
(unstable, transmute_generic_consts, "1.70.0", Some(109929)),
/// Allows #[repr(transparent)] on unions (RFC 2645).
Expand Down
23 changes: 23 additions & 0 deletions compiler/rustc_hir_typeck/src/coercion.rs
Original file line number Diff line number Diff line change
Expand Up @@ -625,6 +625,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
)];

let mut has_unsized_tuple_coercion = false;
let mut has_trait_upcasting_coercion = None;

// Keep resolving `CoerceUnsized` and `Unsize` predicates to avoid
// emitting a coercion in cases like `Foo<$1>` -> `Foo<$2>`, where
Expand Down Expand Up @@ -692,6 +693,13 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
// these here and emit a feature error if coercion doesn't fail
// due to another reason.
match impl_source {
traits::ImplSource::Builtin(
BuiltinImplSource::TraitUpcasting { .. },
_,
) => {
has_trait_upcasting_coercion =
Some((trait_pred.self_ty(), trait_pred.trait_ref.args.type_at(1)));
}
traits::ImplSource::Builtin(BuiltinImplSource::TupleUnsizing, _) => {
has_unsized_tuple_coercion = true;
}
Expand All @@ -702,6 +710,21 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
}
}

if let Some((sub, sup)) = has_trait_upcasting_coercion
&& !self.tcx().features().trait_upcasting
{
// Renders better when we erase regions, since they're not really the point here.
let (sub, sup) = self.tcx.erase_regions((sub, sup));
let mut err = feature_err(
&self.tcx.sess,
sym::trait_upcasting,
self.cause.span,
format!("cannot cast `{sub}` to `{sup}`, trait upcasting coercion is experimental"),
);
err.note(format!("required when coercing `{source}` into `{target}`"));
err.emit();
}

if has_unsized_tuple_coercion && !self.tcx.features().unsized_tuple_coercion {
feature_err(
&self.tcx.sess,
Expand Down
13 changes: 11 additions & 2 deletions compiler/rustc_lint/src/deref_into_dyn_supertrait.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,17 @@ use crate::{

use rustc_hir as hir;
use rustc_middle::ty;
use rustc_session::lint::FutureIncompatibilityReason;
use rustc_span::sym;
use rustc_trait_selection::traits::supertraits;

declare_lint! {
/// The `deref_into_dyn_supertrait` lint is output whenever there is a use of the
/// `Deref` implementation with a `dyn SuperTrait` type as `Output`.
///
/// These implementations will become shadowed when the `trait_upcasting` feature is stabilized.
/// The `deref` functions will no longer be called implicitly, so there might be behavior change.
///
/// ### Example
///
/// ```rust,compile_fail
Expand Down Expand Up @@ -40,10 +44,15 @@ declare_lint! {
///
/// ### Explanation
///
/// The implicit dyn upcasting coercion take priority over those `Deref` impls.
/// The dyn upcasting coercion feature adds new coercion rules, taking priority
/// over certain other coercion rules, which will cause some behavior change.
pub DEREF_INTO_DYN_SUPERTRAIT,
Warn,
"`Deref` implementation usage with a supertrait trait object for output are shadow by implicit coercion",
"`Deref` implementation usage with a supertrait trait object for output might be shadowed in the future",
@future_incompatible = FutureIncompatibleInfo {
reason: FutureIncompatibilityReason::FutureReleaseSemanticsChange,
reference: "issue #89460 <https://github.com/rust-lang/rust/issues/89460>",
};
}

declare_lint_pass!(DerefIntoDynSupertrait => [DEREF_INTO_DYN_SUPERTRAIT]);
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_lint/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
#![feature(iter_intersperse)]
#![feature(iter_order_by)]
#![feature(let_chains)]
#![cfg_attr(not(bootstrap), feature(trait_upcasting))]
#![feature(min_specialization)]
#![feature(never_type)]
#![feature(rustc_attrs)]
Expand Down
1 change: 0 additions & 1 deletion compiler/rustc_lint/src/lints.rs
Original file line number Diff line number Diff line change
Expand Up @@ -532,7 +532,6 @@ pub enum BuiltinSpecialModuleNameUsed {
// deref_into_dyn_supertrait.rs
#[derive(LintDiagnostic)]
#[diag(lint_supertrait_as_deref_target)]
#[help]
pub struct SupertraitAsDerefTarget<'a> {
pub self_ty: Ty<'a>,
pub supertrait_principal: PolyExistentialTraitRef<'a>,
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_middle/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
#![feature(associated_type_bounds)]
#![feature(rustc_attrs)]
#![feature(control_flow_enum)]
#![cfg_attr(not(bootstrap), feature(trait_upcasting))]
#![feature(trusted_step)]
#![feature(try_blocks)]
#![feature(try_reserve_kind)]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,13 @@
use hir::def_id::DefId;
use hir::LangItem;
use rustc_hir as hir;
use rustc_infer::traits::ObligationCause;
use rustc_infer::traits::{Obligation, PolyTraitObligation, SelectionError};
use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams};
use rustc_middle::ty::{self, Ty, TypeVisitableExt};

use crate::traits;
use crate::traits::query::evaluate_obligation::InferCtxtExt;
use crate::traits::util;

use super::BuiltinImplConditions;
Expand Down Expand Up @@ -723,6 +726,45 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
})
}

/// Temporary migration for #89190
fn need_migrate_deref_output_trait_object(
&mut self,
ty: Ty<'tcx>,
param_env: ty::ParamEnv<'tcx>,
cause: &ObligationCause<'tcx>,
) -> Option<ty::PolyExistentialTraitRef<'tcx>> {
let tcx = self.tcx();
if tcx.features().trait_upcasting {
return None;
}

// <ty as Deref>
let trait_ref = ty::TraitRef::new(tcx, tcx.lang_items().deref_trait()?, [ty]);

let obligation =
traits::Obligation::new(tcx, cause.clone(), param_env, ty::Binder::dummy(trait_ref));
if !self.infcx.predicate_may_hold(&obligation) {
return None;
}

self.infcx.probe(|_| {
let ty = traits::normalize_projection_type(
self,
param_env,
ty::AliasTy::new(tcx, tcx.lang_items().deref_target()?, trait_ref.args),
cause.clone(),
0,
// We're *intentionally* throwing these away,
// since we don't actually use them.
&mut vec![],
)
.ty()
.unwrap();

if let ty::Dynamic(data, ..) = ty.kind() { data.principal() } else { None }
})
}

/// Searches for unsizing that might apply to `obligation`.
fn assemble_candidates_for_unsizing(
&mut self,
Expand Down Expand Up @@ -780,6 +822,15 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
let principal_a = a_data.principal().unwrap();
let target_trait_did = principal_def_id_b.unwrap();
let source_trait_ref = principal_a.with_self_ty(self.tcx(), source);
if let Some(deref_trait_ref) = self.need_migrate_deref_output_trait_object(
source,
obligation.param_env,
&obligation.cause,
) {
if deref_trait_ref.def_id() == target_trait_did {
return;
}
}

for (idx, upcast_trait_ref) in
util::supertraits(self.tcx(), source_trait_ref).enumerate()
Expand Down
1 change: 1 addition & 0 deletions library/core/tests/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,7 @@
#![feature(slice_flatten)]
#![feature(error_generic_member_access)]
#![feature(error_in_core)]
#![cfg_attr(not(bootstrap), feature(trait_upcasting))]
#![feature(utf8_chunks)]
#![feature(is_ascii_octdigit)]
#![feature(get_many_mut)]
Expand Down
27 changes: 27 additions & 0 deletions src/doc/unstable-book/src/language-features/trait-upcasting.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# `trait_upcasting`

The tracking issue for this feature is: [#65991]

[#65991]: https://github.com/rust-lang/rust/issues/65991

------------------------

The `trait_upcasting` feature adds support for trait upcasting coercion. This allows a
trait object of type `dyn Bar` to be cast to a trait object of type `dyn Foo`
so long as `Bar: Foo`.

```rust,edition2018
#![feature(trait_upcasting)]
#![allow(incomplete_features)]

trait Foo {}

trait Bar: Foo {}

impl Foo for i32 {}

impl<T: Foo + ?Sized> Bar for T {}

let bar: &dyn Bar = &123;
let foo: &dyn Foo = bar;
```
2 changes: 1 addition & 1 deletion src/tools/miri/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
#![feature(nonzero_ops)]
#![feature(let_chains)]
#![feature(lint_reasons)]
#![feature(int_roundings)]
#![cfg_attr(not(bootstrap), feature(trait_upcasting))]
// Configure clippy and other lints
#![allow(
clippy::collapsible_else_if,
Expand Down
3 changes: 3 additions & 0 deletions src/tools/miri/tests/fail/dyn-upcast-trait-mismatch.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
#![feature(trait_upcasting)]
#![allow(incomplete_features)]

trait Foo: PartialEq<i32> + std::fmt::Debug + Send + Sync {
fn a(&self) -> i32 {
10
Expand Down
3 changes: 2 additions & 1 deletion src/tools/miri/tests/pass/box-custom-alloc.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
//@revisions: stack tree
//@[tree]compile-flags: -Zmiri-tree-borrows
#![feature(allocator_api)]
#![allow(incomplete_features)] // for trait upcasting
#![feature(allocator_api, trait_upcasting)]

use std::alloc::Layout;
use std::alloc::{AllocError, Allocator};
Expand Down
3 changes: 3 additions & 0 deletions src/tools/miri/tests/pass/dyn-upcast.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
#![feature(trait_upcasting)]
#![allow(incomplete_features)]

fn main() {
basic();
diamond();
Expand Down
1 change: 1 addition & 0 deletions tests/ui/codegen/issue-99551.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
// build-pass
#![feature(trait_upcasting)]

pub trait A {}
pub trait B {}
Expand Down
2 changes: 1 addition & 1 deletion tests/ui/dyn-star/no-unsize-coerce-dyn-trait.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#![feature(dyn_star)]
#![feature(dyn_star, trait_upcasting)]
//~^ WARN the feature `dyn_star` is incomplete and may not be safe to use and/or cause compiler crashes

trait A: B {}
Expand Down
2 changes: 1 addition & 1 deletion tests/ui/dyn-star/no-unsize-coerce-dyn-trait.stderr
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
warning: the feature `dyn_star` is incomplete and may not be safe to use and/or cause compiler crashes
--> $DIR/no-unsize-coerce-dyn-trait.rs:1:12
|
LL | #![feature(dyn_star)]
LL | #![feature(dyn_star, trait_upcasting)]
| ^^^^^^^^
|
= note: see issue #102425 <https://github.com/rust-lang/rust/issues/102425> for more information
Expand Down
2 changes: 1 addition & 1 deletion tests/ui/dyn-star/upcast.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// known-bug: #104800

#![feature(dyn_star)]
#![feature(dyn_star, trait_upcasting)]

trait Foo: Bar {
fn hello(&self);
Expand Down
2 changes: 1 addition & 1 deletion tests/ui/dyn-star/upcast.stderr
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
warning: the feature `dyn_star` is incomplete and may not be safe to use and/or cause compiler crashes
--> $DIR/upcast.rs:3:12
|
LL | #![feature(dyn_star)]
LL | #![feature(dyn_star, trait_upcasting)]
| ^^^^^^^^
|
= note: see issue #102425 <https://github.com/rust-lang/rust/issues/102425> for more information
Expand Down
13 changes: 13 additions & 0 deletions tests/ui/feature-gates/feature-gate-trait_upcasting.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
trait Foo {}

trait Bar: Foo {}

impl Foo for () {}

impl Bar for () {}

fn main() {
let bar: &dyn Bar = &();
let foo: &dyn Foo = bar;
//~^ ERROR trait upcasting coercion is experimental [E0658]
}
14 changes: 14 additions & 0 deletions tests/ui/feature-gates/feature-gate-trait_upcasting.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
error[E0658]: cannot cast `dyn Bar` to `dyn Foo`, trait upcasting coercion is experimental
--> $DIR/feature-gate-trait_upcasting.rs:11:25
|
LL | let foo: &dyn Foo = bar;
| ^^^
|
= note: see issue #65991 <https://github.com/rust-lang/rust/issues/65991> for more information
= help: add `#![feature(trait_upcasting)]` to the crate attributes to enable
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
= note: required when coercing `&dyn Bar` into `&dyn Foo`

error: aborting due to 1 previous error

For more information about this error, try `rustc --explain E0658`.
1 change: 1 addition & 0 deletions tests/ui/traits/next-solver/normalize-unsize-rhs.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
// compile-flags: -Znext-solver
// check-pass
#![feature(trait_upcasting)]

trait A {}
trait B: A {}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
// check-pass
// compile-flags: -Znext-solver
#![feature(trait_upcasting)]

pub trait A {}
pub trait B: A {}
Expand Down
1 change: 1 addition & 0 deletions tests/ui/traits/next-solver/upcast-right-substs.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
// compile-flags: -Znext-solver
// check-pass
#![feature(trait_upcasting)]

trait Foo: Bar<i32> + Bar<u32> {}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
#![feature(trait_upcasting)]
#![feature(trait_alias)]

// Although we *elaborate* `T: Alias` to `i32: B`, we should
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
error[E0308]: mismatched types
--> $DIR/alias-where-clause-isnt-supertrait.rs:26:5
--> $DIR/alias-where-clause-isnt-supertrait.rs:27:5
|
LL | fn test(x: &dyn C) -> &dyn B {
| ------ expected `&dyn B` because of return type
Expand Down
2 changes: 2 additions & 0 deletions tests/ui/traits/trait-upcasting/basic.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
// run-pass

#![feature(trait_upcasting)]

trait Foo: PartialEq<i32> + std::fmt::Debug + Send + Sync {
fn a(&self) -> i32 {
10
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
// run-pass
#![feature(trait_upcasting)]

trait Foo<T: Default + ToString>: Bar<i32> + Bar<T> {}
trait Bar<T: Default + ToString> {
Expand Down
14 changes: 0 additions & 14 deletions tests/ui/traits/trait-upcasting/deref-lint-regions.stderr

This file was deleted.

Loading
Loading