Skip to content

Commit

Permalink
Compiler: Rename "object safe" to "dyn compatible"
Browse files Browse the repository at this point in the history
  • Loading branch information
fmease committed Sep 25, 2024
1 parent f5cd2c5 commit 236e368
Show file tree
Hide file tree
Showing 183 changed files with 518 additions and 506 deletions.
2 changes: 1 addition & 1 deletion compiler/rustc_const_eval/src/interpret/call.rs
Original file line number Diff line number Diff line change
Expand Up @@ -598,7 +598,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
// codegen'd / interpreted as virtual calls through the vtable.
ty::InstanceKind::Virtual(def_id, idx) => {
let mut args = args.to_vec();
// We have to implement all "object safe receivers". So we have to go search for a
// We have to implement all "dyn-compatible receivers". So we have to go search for a
// pointer or `dyn Trait` type, but it could be wrapped in newtypes. So recursively
// unwrap those newtypes until we are there.
// An `InPlace` does nothing here, we keep the original receiver intact. We can't
Expand Down
33 changes: 18 additions & 15 deletions compiler/rustc_error_codes/src/error_codes/E0038.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@ trait, written in type positions) but this was a bit too confusing, so we now
write `dyn Trait`.

Some traits are not allowed to be used as trait object types. The traits that
are allowed to be used as trait object types are called "object-safe" traits.
Attempting to use a trait object type for a trait that is not object-safe will
trigger error E0038.
are allowed to be used as trait object types are called "dyn-compatible"[^1]
traits. Attempting to use a trait object type for a trait that is not
dyn-compatible will trigger error E0038.

Two general aspects of trait object types give rise to the restrictions:

Expand All @@ -25,13 +25,16 @@ Two general aspects of trait object types give rise to the restrictions:
objects with the same trait object type may point to vtables from different
implementations.

The specific conditions that violate object-safety follow, most of which relate
to missing size information and vtable polymorphism arising from these aspects.
The specific conditions that violate dyn-compatibility follow, most of which
relate to missing size information and vtable polymorphism arising from these
aspects.

[^1]: Formerly known as "object-safe".

### The trait requires `Self: Sized`

Traits that are declared as `Trait: Sized` or which otherwise inherit a
constraint of `Self:Sized` are not object-safe.
constraint of `Self:Sized` are not dyn-compatible.

The reasoning behind this is somewhat subtle. It derives from the fact that Rust
requires (and defines) that every trait object type `dyn Trait` automatically
Expand All @@ -58,7 +61,7 @@ implement a sized trait like `Trait:Sized`. So, rather than allow an exception
to the rule that `dyn Trait` always implements `Trait`, Rust chooses to prohibit
such a `dyn Trait` from existing at all.

Only unsized traits are considered object-safe.
Only unsized traits are considered dyn-compatible.

Generally, `Self: Sized` is used to indicate that the trait should not be used
as a trait object. If the trait comes from your own crate, consider removing
Expand Down Expand Up @@ -103,8 +106,8 @@ fn call_foo(x: Box<dyn Trait>) {
}
```

If only some methods aren't object-safe, you can add a `where Self: Sized` bound
on them to mark them as explicitly unavailable to trait objects. The
If only some methods aren't dyn-compatible, you can add a `where Self: Sized`
bound on them to mark them as explicitly unavailable to trait objects. The
functionality will still be available to all other implementers, including
`Box<dyn Trait>` which is itself sized (assuming you `impl Trait for Box<dyn
Trait>`).
Expand All @@ -117,7 +120,7 @@ trait Trait {
```

Now, `foo()` can no longer be called on a trait object, but you will now be
allowed to make a trait object, and that will be able to call any object-safe
allowed to make a trait object, and that will be able to call any dyn-compatible
methods. With such a bound, one can still call `foo()` on types implementing
that trait that aren't behind trait objects.

Expand Down Expand Up @@ -306,18 +309,18 @@ Here, the supertrait might have methods as follows:

```
trait Super<A: ?Sized> {
fn get_a(&self) -> &A; // note that this is object safe!
fn get_a(&self) -> &A; // note that this is dyn-compatible!
}
```

If the trait `Trait` was deriving from something like `Super<String>` or
`Super<T>` (where `Foo` itself is `Foo<T>`), this is okay, because given a type
`get_a()` will definitely return an object of that type.

However, if it derives from `Super<Self>`, even though `Super` is object safe,
the method `get_a()` would return an object of unknown type when called on the
function. `Self` type parameters let us make object safe traits no longer safe,
so they are forbidden when specifying supertraits.
However, if it derives from `Super<Self>`, even though `Super` is
dyn-compatible, the method `get_a()` would return an object of unknown type when
called on the function. `Self` type parameters let us make dyn-compatible traits
no longer compatible, so they are forbidden when specifying supertraits.

There's no easy fix for this. Generally, code will need to be refactored so that
you no longer need to derive from `Super<Self>`.
2 changes: 1 addition & 1 deletion compiler/rustc_error_codes/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -623,7 +623,7 @@ E0800: 0800,
// E0314, // closure outlives stack frame
// E0315, // cannot invoke closure outside of its lifetime
// E0319, // trait impls for defaulted traits allowed just for structs/enums
// E0372, // coherence not object safe
// E0372, // coherence not dyn-compatible
// E0385, // {} in an aliasable location
// E0402, // cannot use an outer type parameter in this context
// E0406, // merged into 420
Expand Down
5 changes: 4 additions & 1 deletion compiler/rustc_feature/src/unstable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -548,9 +548,12 @@ declare_features! (
(unstable, non_exhaustive_omitted_patterns_lint, "1.57.0", Some(89554)),
/// Allows `for<T>` binders in where-clauses
(incomplete, non_lifetime_binders, "1.69.0", Some(108185)),
/// Allows making `dyn Trait` well-formed even if `Trait` is not object safe.
/// Allows making `dyn Trait` well-formed even if `Trait` is not dyn-compatible[^1].
/// In that case, `dyn Trait: Trait` does not hold. Moreover, coercions and
/// casts in safe Rust to `dyn Trait` for such a `Trait` is also forbidden.
///
/// [^1]: Formerly known as "object safe".
// FIXME(dyn_compat_renaming): Rename feature.
(unstable, object_safe_for_dispatch, "1.40.0", Some(43561)),
/// Allows using enums in offset_of!
(unstable, offset_of_enum, "1.75.0", Some(120141)),
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_hir_analysis/messages.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -558,7 +558,7 @@ hir_analysis_unrecognized_intrinsic_function =
.help = if you're adding an intrinsic, be sure to update `check_intrinsic_type`
hir_analysis_unused_associated_type_bounds =
unnecessary associated type bound for not object safe associated type
unnecessary associated type bound for dyn-incompatible associated type
.note = this associated type has a `where Self: Sized` bound, and while the associated type can be specified, it cannot be used because trait objects are never `Sized`
.suggestion = remove this bound
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_hir_analysis/src/check/wfcheck.rs
Original file line number Diff line number Diff line change
Expand Up @@ -872,7 +872,7 @@ fn check_object_unsafe_self_trait_by_name(tcx: TyCtxt<'_>, item: &hir::TraitItem
_ => {}
}
if !trait_should_be_self.is_empty() {
if tcx.is_object_safe(trait_def_id) {
if tcx.is_dyn_compatible(trait_def_id) {
return;
}
let sugg = trait_should_be_self.iter().map(|span| (*span, "Self".to_string())).collect();
Expand Down
7 changes: 4 additions & 3 deletions compiler/rustc_hir_analysis/src/coherence/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -179,8 +179,8 @@ fn check_object_overlap<'tcx>(

// check for overlap with the automatic `impl Trait for dyn Trait`
if let ty::Dynamic(data, ..) = trait_ref.self_ty().kind() {
// This is something like impl Trait1 for Trait2. Illegal
// if Trait1 is a supertrait of Trait2 or Trait2 is not object safe.
// This is something like `impl Trait1 for Trait2`. Illegal if
// Trait1 is a supertrait of Trait2 or Trait2 is not dyn-compatible.

let component_def_ids = data.iter().flat_map(|predicate| {
match predicate.skip_binder() {
Expand All @@ -193,7 +193,8 @@ fn check_object_overlap<'tcx>(
});

for component_def_id in component_def_ids {
if !tcx.is_object_safe(component_def_id) {
if !tcx.is_dyn_compatible(component_def_id) {
// FIXME(dyn_compat_renaming): Rename test and update comment.
// Without the 'object_safe_for_dispatch' feature this is an error
// which will be reported by wfcheck. Ignore it here.
// This is tested by `coherence-impl-trait-for-trait-object-safe.rs`.
Expand Down
10 changes: 5 additions & 5 deletions compiler/rustc_hir_analysis/src/coherence/orphan.rs
Original file line number Diff line number Diff line change
Expand Up @@ -109,16 +109,16 @@ pub(crate) fn orphan_check_impl(
//
// auto trait AutoTrait {}
//
// trait ObjectSafeTrait {
// trait DynCompatibleTrait {
// fn f(&self) where Self: AutoTrait;
// }
//
// We can allow f to be called on `dyn ObjectSafeTrait + AutoTrait`.
// We can allow f to be called on `dyn DynCompatibleTrait + AutoTrait`.
//
// If we didn't deny `impl AutoTrait for dyn Trait`, it would be unsound
// for the ObjectSafeTrait shown above to be object safe because someone
// could take some type implementing ObjectSafeTrait but not AutoTrait,
// unsize it to `dyn ObjectSafeTrait`, and call .f() which has no
// for the `DynCompatibleTrait` shown above to be dyn-compatible because someone
// could take some type implementing `DynCompatibleTrait` but not `AutoTrait`,
// unsize it to `dyn DynCompatibleTrait`, and call `.f()` which has no
// concrete implementation (issue #50781).
enum LocalImpl {
Allow,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ use rustc_middle::ty::{
self, DynKind, ExistentialPredicateStableCmpExt as _, Ty, TyCtxt, TypeFoldable, Upcast,
};
use rustc_span::{ErrorGuaranteed, Span};
use rustc_trait_selection::error_reporting::traits::report_object_safety_error;
use rustc_trait_selection::traits::{self, hir_ty_lowering_object_safety_violations};
use rustc_trait_selection::error_reporting::traits::report_dyn_incompatibility;
use rustc_trait_selection::traits::{self, hir_ty_lowering_dyn_compatibility_violations};
use smallvec::{SmallVec, smallvec};
use tracing::{debug, instrument};

Expand Down Expand Up @@ -99,19 +99,19 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
return Ty::new_error(tcx, reported);
}

// Check that there are no gross object safety violations;
// Check that there are no gross dyn-compatibility violations;
// most importantly, that the supertraits don't contain `Self`,
// to avoid ICEs.
for item in &regular_traits {
let object_safety_violations =
hir_ty_lowering_object_safety_violations(tcx, item.trait_ref().def_id());
if !object_safety_violations.is_empty() {
let reported = report_object_safety_error(
let violations =
hir_ty_lowering_dyn_compatibility_violations(tcx, item.trait_ref().def_id());
if !violations.is_empty() {
let reported = report_dyn_incompatibility(
tcx,
span,
Some(hir_id),
item.trait_ref().def_id(),
&object_safety_violations,
&violations,
)
.emit();
return Ty::new_error(tcx, reported);
Expand Down Expand Up @@ -275,8 +275,10 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
tcx.item_name(def_id),
)
.with_note(
rustc_middle::traits::ObjectSafetyViolation::SupertraitSelf(smallvec![])
.error_msg(),
rustc_middle::traits::DynCompatibilityViolation::SupertraitSelf(
smallvec![],
)
.error_msg(),
)
.emit();
}
Expand Down
14 changes: 7 additions & 7 deletions compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,9 @@ use rustc_session::parse::feature_err;
use rustc_span::edit_distance::find_best_match_for_name;
use rustc_span::symbol::{Ident, kw, sym};
use rustc_span::{BytePos, DUMMY_SP, Span, Symbol};
use rustc_trait_selection::error_reporting::traits::report_object_safety_error;
use rustc_trait_selection::error_reporting::traits::report_dyn_incompatibility;
use rustc_trait_selection::traits::{
FulfillmentError, TraitAliasExpansionInfo, object_safety_violations_for_assoc_item,
FulfillmentError, TraitAliasExpansionInfo, dyn_compatibility_violations_for_assoc_item,
};

use crate::errors::{
Expand Down Expand Up @@ -739,7 +739,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
// Account for things like `dyn Foo + 'a`, like in tests `issue-22434.rs` and
// `issue-22560.rs`.
let mut trait_bound_spans: Vec<Span> = vec![];
let mut object_safety_violations = false;
let mut dyn_compatibility_violations = false;
for (span, items) in &associated_types {
if !items.is_empty() {
trait_bound_spans.push(*span);
Expand All @@ -750,14 +750,14 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
names_len += 1;

let violations =
object_safety_violations_for_assoc_item(tcx, trait_def_id, *assoc_item);
dyn_compatibility_violations_for_assoc_item(tcx, trait_def_id, *assoc_item);
if !violations.is_empty() {
report_object_safety_error(tcx, *span, None, trait_def_id, &violations).emit();
object_safety_violations = true;
report_dyn_incompatibility(tcx, *span, None, trait_def_id, &violations).emit();
dyn_compatibility_violations = true;
}
}
}
if object_safety_violations {
if dyn_compatibility_violations {
return;
}

Expand Down
22 changes: 11 additions & 11 deletions compiler/rustc_hir_analysis/src/hir_ty_lowering/lint.rs
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
if self_ty.span.can_be_used_for_suggestions()
&& !self.maybe_suggest_impl_trait(self_ty, &mut diag)
{
// FIXME: Only emit this suggestion if the trait is object safe.
// FIXME: Only emit this suggestion if the trait is dyn-compatible.
diag.multipart_suggestion_verbose(label, sugg, Applicability::MachineApplicable);
}
// Check if the impl trait that we are considering is an impl of a local trait.
Expand All @@ -89,7 +89,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
lint.primary_message("trait objects without an explicit `dyn` are deprecated");
if self_ty.span.can_be_used_for_suggestions() {
lint.multipart_suggestion_verbose(
"if this is an object-safe trait, use `dyn`",
"if this is a dyn-compatible trait, use `dyn`",
sugg,
Applicability::MachineApplicable,
);
Expand Down Expand Up @@ -196,15 +196,15 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
let mut is_downgradable = true;

// Check if trait object is safe for suggesting dynamic dispatch.
let is_object_safe = match self_ty.kind {
let is_dyn_compatible = match self_ty.kind {
hir::TyKind::TraitObject(objects, ..) => {
objects.iter().all(|(o, _)| match o.trait_ref.path.res {
Res::Def(DefKind::Trait, id) => {
if Some(id) == owner {
// For recursive traits, don't downgrade the error. (#119652)
is_downgradable = false;
}
tcx.is_object_safe(id)
tcx.is_dyn_compatible(id)
}
_ => false,
})
Expand All @@ -221,8 +221,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
if let hir::FnRetTy::Return(ty) = sig.decl.output
&& ty.peel_refs().hir_id == self_ty.hir_id
{
let pre = if !is_object_safe {
format!("`{trait_name}` is not object safe, ")
let pre = if !is_dyn_compatible {
format!("`{trait_name}` is dyn-incompatible, ")
} else {
String::new()
};
Expand All @@ -234,7 +234,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
diag.multipart_suggestion_verbose(msg, impl_sugg, Applicability::MachineApplicable);

// Suggest `Box<dyn Trait>` for return type
if is_object_safe {
if is_dyn_compatible {
// If the return type is `&Trait`, we don't want
// the ampersand to be displayed in the `Box<dyn Trait>`
// suggestion.
Expand All @@ -253,7 +253,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
Applicability::MachineApplicable,
);
} else if is_downgradable {
// We'll emit the object safety error already, with a structured suggestion.
// We'll emit the dyn-compatibility error already, with a structured suggestion.
diag.downgrade_to_delayed_bug();
}
return true;
Expand All @@ -276,10 +276,10 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
impl_sugg,
Applicability::MachineApplicable,
);
if !is_object_safe {
diag.note(format!("`{trait_name}` it is not object safe, so it can't be `dyn`"));
if !is_dyn_compatible {
diag.note(format!("`{trait_name}` it is dyn-incompatible, so it can't be `dyn`"));
if is_downgradable {
// We'll emit the object safety error already, with a structured suggestion.
// We'll emit the dyn-compatibility error already, with a structured suggestion.
diag.downgrade_to_delayed_bug();
}
} else {
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,10 @@

mod bounds;
mod cmse;
mod dyn_compatibility;
pub mod errors;
pub mod generics;
mod lint;
mod object_safety;

use std::slice;

Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_hir_typeck/src/coercion.rs
Original file line number Diff line number Diff line change
Expand Up @@ -655,7 +655,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
return Err(TypeError::Mismatch);
}

// Object safety violations or miscellaneous.
// Dyn-compatibility violations or miscellaneous.
Err(err) => {
self.err_ctxt().report_selection_error(obligation.clone(), &obligation, &err);
// Treat this like an obligation and follow through
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -757,7 +757,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// give us a `QPath::TypeRelative` with a trait object as
// `qself`. In that case, we want to avoid registering a WF obligation
// for `dyn MyTrait`, since we don't actually need the trait
// to be object-safe.
// to be dyn-compatible.
// We manually call `register_wf_obligation` in the success path
// below.
let ty = self.lowerer().lower_ty(qself);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
| ty::PredicateKind::Clause(ty::ClauseKind::RegionOutlives(..))
| ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(..))
| ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(..))
| ty::PredicateKind::ObjectSafe(..)
| ty::PredicateKind::DynCompatible(..)
| ty::PredicateKind::NormalizesTo(..)
| ty::PredicateKind::AliasRelate(..)
| ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(..))
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_hir_typeck/src/method/confirm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -292,7 +292,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
// distinct types (e.g., if `Self` appeared as an
// argument type), but those cases have already
// been ruled out when we deemed the trait to be
// "object safe".
// "dyn-compatible".
let original_poly_trait_ref = principal.with_self_ty(this.tcx, object_ty);
let upcast_poly_trait_ref = this.upcast(original_poly_trait_ref, trait_def_id);
let upcast_trait_ref =
Expand Down
Loading

0 comments on commit 236e368

Please sign in to comment.