mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-12-27 05:23:24 +00:00
Auto merge of #18205 - noahmbright:object_safety, r=HKalbasi
Rename object_safety First PR here (yay!), so I read some of the getting started docs. There are a couple references to `handlers.rs`, which as far as I can tell has been refactored into `handlers/*.rs`. I made some tweaks to that in one commit. There is one fixme about a function called `to_lsp_runnable`, which I can't find anywhere at all. I can update that if I get some more info there. Otherwise I changed references to object safety, is object safe, etc., trying to match case/style as I went. There was one case I found where there's a trait from somewhere else called `is_object_safe`, which I found defined in my cargo registry. I didn't touch that for now, just marked it with a fixme
This commit is contained in:
commit
822644d97d
16 changed files with 117 additions and 109 deletions
|
@ -382,8 +382,9 @@ impl chalk_solve::RustIrDatabase<Interner> for ChalkContext<'_> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_object_safe(&self, trait_id: chalk_ir::TraitId<Interner>) -> bool {
|
fn is_object_safe(&self, trait_id: chalk_ir::TraitId<Interner>) -> bool {
|
||||||
|
// FIXME: When cargo is updated, change to dyn_compatibility
|
||||||
let trait_ = from_chalk_trait_id(trait_id);
|
let trait_ = from_chalk_trait_id(trait_id);
|
||||||
crate::object_safety::object_safety(self.db, trait_).is_none()
|
crate::dyn_compatibility::dyn_compatibility(self.db, trait_).is_none()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn closure_kind(
|
fn closure_kind(
|
||||||
|
|
|
@ -20,11 +20,11 @@ use triomphe::Arc;
|
||||||
use crate::{
|
use crate::{
|
||||||
chalk_db,
|
chalk_db,
|
||||||
consteval::ConstEvalError,
|
consteval::ConstEvalError,
|
||||||
|
dyn_compatibility::DynCompatibilityViolation,
|
||||||
layout::{Layout, LayoutError},
|
layout::{Layout, LayoutError},
|
||||||
lower::{GenericDefaults, GenericPredicates},
|
lower::{GenericDefaults, GenericPredicates},
|
||||||
method_resolution::{InherentImpls, TraitImpls, TyFingerprint},
|
method_resolution::{InherentImpls, TraitImpls, TyFingerprint},
|
||||||
mir::{BorrowckResult, MirBody, MirLowerError},
|
mir::{BorrowckResult, MirBody, MirLowerError},
|
||||||
object_safety::ObjectSafetyViolation,
|
|
||||||
Binders, ClosureId, Const, FnDefId, ImplTraitId, ImplTraits, InferenceResult, Interner,
|
Binders, ClosureId, Const, FnDefId, ImplTraitId, ImplTraits, InferenceResult, Interner,
|
||||||
PolyFnSig, Substitution, TraitEnvironment, TraitRef, Ty, TyDefId, ValueTyDefId,
|
PolyFnSig, Substitution, TraitEnvironment, TraitRef, Ty, TyDefId, ValueTyDefId,
|
||||||
};
|
};
|
||||||
|
@ -108,8 +108,8 @@ pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> {
|
||||||
#[salsa::invoke(crate::layout::target_data_layout_query)]
|
#[salsa::invoke(crate::layout::target_data_layout_query)]
|
||||||
fn target_data_layout(&self, krate: CrateId) -> Result<Arc<TargetDataLayout>, Arc<str>>;
|
fn target_data_layout(&self, krate: CrateId) -> Result<Arc<TargetDataLayout>, Arc<str>>;
|
||||||
|
|
||||||
#[salsa::invoke(crate::object_safety::object_safety_of_trait_query)]
|
#[salsa::invoke(crate::dyn_compatibility::dyn_compatibility_of_trait_query)]
|
||||||
fn object_safety_of_trait(&self, trait_: TraitId) -> Option<ObjectSafetyViolation>;
|
fn dyn_compatibility_of_trait(&self, trait_: TraitId) -> Option<DynCompatibilityViolation>;
|
||||||
|
|
||||||
#[salsa::invoke(crate::lower::ty_query)]
|
#[salsa::invoke(crate::lower::ty_query)]
|
||||||
#[salsa::cycle(crate::lower::ty_recover)]
|
#[salsa::cycle(crate::lower::ty_recover)]
|
||||||
|
@ -280,8 +280,8 @@ pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn hir_database_is_object_safe() {
|
fn hir_database_is_dyn_compatible() {
|
||||||
fn _assert_object_safe(_: &dyn HirDatabase) {}
|
fn _assert_dyn_compatible(_: &dyn HirDatabase) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
//! Compute the object-safety of a trait
|
//! Compute the dyn-compatibility of a trait
|
||||||
|
|
||||||
use std::ops::ControlFlow;
|
use std::ops::ControlFlow;
|
||||||
|
|
||||||
|
@ -28,14 +28,14 @@ use crate::{
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||||
pub enum ObjectSafetyViolation {
|
pub enum DynCompatibilityViolation {
|
||||||
SizedSelf,
|
SizedSelf,
|
||||||
SelfReferential,
|
SelfReferential,
|
||||||
Method(FunctionId, MethodViolationCode),
|
Method(FunctionId, MethodViolationCode),
|
||||||
AssocConst(ConstId),
|
AssocConst(ConstId),
|
||||||
GAT(TypeAliasId),
|
GAT(TypeAliasId),
|
||||||
// This doesn't exist in rustc, but added for better visualization
|
// This doesn't exist in rustc, but added for better visualization
|
||||||
HasNonSafeSuperTrait(TraitId),
|
HasNonCompatibleSuperTrait(TraitId),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||||
|
@ -50,70 +50,73 @@ pub enum MethodViolationCode {
|
||||||
UndispatchableReceiver,
|
UndispatchableReceiver,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn object_safety(db: &dyn HirDatabase, trait_: TraitId) -> Option<ObjectSafetyViolation> {
|
pub fn dyn_compatibility(
|
||||||
|
db: &dyn HirDatabase,
|
||||||
|
trait_: TraitId,
|
||||||
|
) -> Option<DynCompatibilityViolation> {
|
||||||
for super_trait in all_super_traits(db.upcast(), trait_).into_iter().skip(1).rev() {
|
for super_trait in all_super_traits(db.upcast(), trait_).into_iter().skip(1).rev() {
|
||||||
if db.object_safety_of_trait(super_trait).is_some() {
|
if db.dyn_compatibility_of_trait(super_trait).is_some() {
|
||||||
return Some(ObjectSafetyViolation::HasNonSafeSuperTrait(super_trait));
|
return Some(DynCompatibilityViolation::HasNonCompatibleSuperTrait(super_trait));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
db.object_safety_of_trait(trait_)
|
db.dyn_compatibility_of_trait(trait_)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn object_safety_with_callback<F>(
|
pub fn dyn_compatibility_with_callback<F>(
|
||||||
db: &dyn HirDatabase,
|
db: &dyn HirDatabase,
|
||||||
trait_: TraitId,
|
trait_: TraitId,
|
||||||
cb: &mut F,
|
cb: &mut F,
|
||||||
) -> ControlFlow<()>
|
) -> ControlFlow<()>
|
||||||
where
|
where
|
||||||
F: FnMut(ObjectSafetyViolation) -> ControlFlow<()>,
|
F: FnMut(DynCompatibilityViolation) -> ControlFlow<()>,
|
||||||
{
|
{
|
||||||
for super_trait in all_super_traits(db.upcast(), trait_).into_iter().skip(1).rev() {
|
for super_trait in all_super_traits(db.upcast(), trait_).into_iter().skip(1).rev() {
|
||||||
if db.object_safety_of_trait(super_trait).is_some() {
|
if db.dyn_compatibility_of_trait(super_trait).is_some() {
|
||||||
cb(ObjectSafetyViolation::HasNonSafeSuperTrait(trait_))?;
|
cb(DynCompatibilityViolation::HasNonCompatibleSuperTrait(trait_))?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
object_safety_of_trait_with_callback(db, trait_, cb)
|
dyn_compatibility_of_trait_with_callback(db, trait_, cb)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn object_safety_of_trait_with_callback<F>(
|
pub fn dyn_compatibility_of_trait_with_callback<F>(
|
||||||
db: &dyn HirDatabase,
|
db: &dyn HirDatabase,
|
||||||
trait_: TraitId,
|
trait_: TraitId,
|
||||||
cb: &mut F,
|
cb: &mut F,
|
||||||
) -> ControlFlow<()>
|
) -> ControlFlow<()>
|
||||||
where
|
where
|
||||||
F: FnMut(ObjectSafetyViolation) -> ControlFlow<()>,
|
F: FnMut(DynCompatibilityViolation) -> ControlFlow<()>,
|
||||||
{
|
{
|
||||||
// Check whether this has a `Sized` bound
|
// Check whether this has a `Sized` bound
|
||||||
if generics_require_sized_self(db, trait_.into()) {
|
if generics_require_sized_self(db, trait_.into()) {
|
||||||
cb(ObjectSafetyViolation::SizedSelf)?;
|
cb(DynCompatibilityViolation::SizedSelf)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if there exist bounds that referencing self
|
// Check if there exist bounds that referencing self
|
||||||
if predicates_reference_self(db, trait_) {
|
if predicates_reference_self(db, trait_) {
|
||||||
cb(ObjectSafetyViolation::SelfReferential)?;
|
cb(DynCompatibilityViolation::SelfReferential)?;
|
||||||
}
|
}
|
||||||
if bounds_reference_self(db, trait_) {
|
if bounds_reference_self(db, trait_) {
|
||||||
cb(ObjectSafetyViolation::SelfReferential)?;
|
cb(DynCompatibilityViolation::SelfReferential)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
// rustc checks for non-lifetime binders here, but we don't support HRTB yet
|
// rustc checks for non-lifetime binders here, but we don't support HRTB yet
|
||||||
|
|
||||||
let trait_data = db.trait_data(trait_);
|
let trait_data = db.trait_data(trait_);
|
||||||
for (_, assoc_item) in &trait_data.items {
|
for (_, assoc_item) in &trait_data.items {
|
||||||
object_safety_violation_for_assoc_item(db, trait_, *assoc_item, cb)?;
|
dyn_compatibility_violation_for_assoc_item(db, trait_, *assoc_item, cb)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
ControlFlow::Continue(())
|
ControlFlow::Continue(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn object_safety_of_trait_query(
|
pub fn dyn_compatibility_of_trait_query(
|
||||||
db: &dyn HirDatabase,
|
db: &dyn HirDatabase,
|
||||||
trait_: TraitId,
|
trait_: TraitId,
|
||||||
) -> Option<ObjectSafetyViolation> {
|
) -> Option<DynCompatibilityViolation> {
|
||||||
let mut res = None;
|
let mut res = None;
|
||||||
object_safety_of_trait_with_callback(db, trait_, &mut |osv| {
|
dyn_compatibility_of_trait_with_callback(db, trait_, &mut |osv| {
|
||||||
res = Some(osv);
|
res = Some(osv);
|
||||||
ControlFlow::Break(())
|
ControlFlow::Break(())
|
||||||
});
|
});
|
||||||
|
@ -321,14 +324,14 @@ fn contains_illegal_self_type_reference<T: TypeVisitable<Interner>>(
|
||||||
t.visit_with(visitor.as_dyn(), outer_binder).is_break()
|
t.visit_with(visitor.as_dyn(), outer_binder).is_break()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn object_safety_violation_for_assoc_item<F>(
|
fn dyn_compatibility_violation_for_assoc_item<F>(
|
||||||
db: &dyn HirDatabase,
|
db: &dyn HirDatabase,
|
||||||
trait_: TraitId,
|
trait_: TraitId,
|
||||||
item: AssocItemId,
|
item: AssocItemId,
|
||||||
cb: &mut F,
|
cb: &mut F,
|
||||||
) -> ControlFlow<()>
|
) -> ControlFlow<()>
|
||||||
where
|
where
|
||||||
F: FnMut(ObjectSafetyViolation) -> ControlFlow<()>,
|
F: FnMut(DynCompatibilityViolation) -> ControlFlow<()>,
|
||||||
{
|
{
|
||||||
// Any item that has a `Self : Sized` requisite is otherwise
|
// Any item that has a `Self : Sized` requisite is otherwise
|
||||||
// exempt from the regulations.
|
// exempt from the regulations.
|
||||||
|
@ -337,10 +340,10 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
match item {
|
match item {
|
||||||
AssocItemId::ConstId(it) => cb(ObjectSafetyViolation::AssocConst(it)),
|
AssocItemId::ConstId(it) => cb(DynCompatibilityViolation::AssocConst(it)),
|
||||||
AssocItemId::FunctionId(it) => {
|
AssocItemId::FunctionId(it) => {
|
||||||
virtual_call_violations_for_method(db, trait_, it, &mut |mvc| {
|
virtual_call_violations_for_method(db, trait_, it, &mut |mvc| {
|
||||||
cb(ObjectSafetyViolation::Method(it, mvc))
|
cb(DynCompatibilityViolation::Method(it, mvc))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
AssocItemId::TypeAliasId(it) => {
|
AssocItemId::TypeAliasId(it) => {
|
||||||
|
@ -350,7 +353,7 @@ where
|
||||||
} else {
|
} else {
|
||||||
let generic_params = db.generic_params(item.into());
|
let generic_params = db.generic_params(item.into());
|
||||||
if !generic_params.is_empty() {
|
if !generic_params.is_empty() {
|
||||||
cb(ObjectSafetyViolation::GAT(it))
|
cb(DynCompatibilityViolation::GAT(it))
|
||||||
} else {
|
} else {
|
||||||
ControlFlow::Continue(())
|
ControlFlow::Continue(())
|
||||||
}
|
}
|
||||||
|
@ -469,7 +472,7 @@ fn receiver_is_dispatchable(
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
|
|
||||||
// `self: Self` can't be dispatched on, but this is already considered object safe.
|
// `self: Self` can't be dispatched on, but this is already considered dyn compatible
|
||||||
// See rustc's comment on https://github.com/rust-lang/rust/blob/3f121b9461cce02a703a0e7e450568849dfaa074/compiler/rustc_trait_selection/src/traits/object_safety.rs#L433-L437
|
// See rustc's comment on https://github.com/rust-lang/rust/blob/3f121b9461cce02a703a0e7e450568849dfaa074/compiler/rustc_trait_selection/src/traits/object_safety.rs#L433-L437
|
||||||
if sig
|
if sig
|
||||||
.skip_binders()
|
.skip_binders()
|
|
@ -5,29 +5,29 @@ use rustc_hash::{FxHashMap, FxHashSet};
|
||||||
use syntax::ToSmolStr;
|
use syntax::ToSmolStr;
|
||||||
use test_fixture::WithFixture;
|
use test_fixture::WithFixture;
|
||||||
|
|
||||||
use crate::{object_safety::object_safety_with_callback, test_db::TestDB};
|
use crate::{dyn_compatibility::dyn_compatibility_with_callback, test_db::TestDB};
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
|
DynCompatibilityViolation,
|
||||||
MethodViolationCode::{self, *},
|
MethodViolationCode::{self, *},
|
||||||
ObjectSafetyViolation,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
use ObjectSafetyViolationKind::*;
|
use DynCompatibilityViolationKind::*;
|
||||||
|
|
||||||
#[allow(clippy::upper_case_acronyms)]
|
#[allow(clippy::upper_case_acronyms)]
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||||
enum ObjectSafetyViolationKind {
|
enum DynCompatibilityViolationKind {
|
||||||
SizedSelf,
|
SizedSelf,
|
||||||
SelfReferential,
|
SelfReferential,
|
||||||
Method(MethodViolationCode),
|
Method(MethodViolationCode),
|
||||||
AssocConst,
|
AssocConst,
|
||||||
GAT,
|
GAT,
|
||||||
HasNonSafeSuperTrait,
|
HasNonCompatibleSuperTrait,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_object_safety<'a>(
|
fn check_dyn_compatibility<'a>(
|
||||||
ra_fixture: &str,
|
ra_fixture: &str,
|
||||||
expected: impl IntoIterator<Item = (&'a str, Vec<ObjectSafetyViolationKind>)>,
|
expected: impl IntoIterator<Item = (&'a str, Vec<DynCompatibilityViolationKind>)>,
|
||||||
) {
|
) {
|
||||||
let mut expected: FxHashMap<_, _> =
|
let mut expected: FxHashMap<_, _> =
|
||||||
expected.into_iter().map(|(id, osvs)| (id, FxHashSet::from_iter(osvs))).collect();
|
expected.into_iter().map(|(id, osvs)| (id, FxHashSet::from_iter(osvs))).collect();
|
||||||
|
@ -53,18 +53,20 @@ fn check_object_safety<'a>(
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
let mut osvs = FxHashSet::default();
|
let mut osvs = FxHashSet::default();
|
||||||
object_safety_with_callback(&db, trait_id, &mut |osv| {
|
dyn_compatibility_with_callback(&db, trait_id, &mut |osv| {
|
||||||
osvs.insert(match osv {
|
osvs.insert(match osv {
|
||||||
ObjectSafetyViolation::SizedSelf => SizedSelf,
|
DynCompatibilityViolation::SizedSelf => SizedSelf,
|
||||||
ObjectSafetyViolation::SelfReferential => SelfReferential,
|
DynCompatibilityViolation::SelfReferential => SelfReferential,
|
||||||
ObjectSafetyViolation::Method(_, mvc) => Method(mvc),
|
DynCompatibilityViolation::Method(_, mvc) => Method(mvc),
|
||||||
ObjectSafetyViolation::AssocConst(_) => AssocConst,
|
DynCompatibilityViolation::AssocConst(_) => AssocConst,
|
||||||
ObjectSafetyViolation::GAT(_) => GAT,
|
DynCompatibilityViolation::GAT(_) => GAT,
|
||||||
ObjectSafetyViolation::HasNonSafeSuperTrait(_) => HasNonSafeSuperTrait,
|
DynCompatibilityViolation::HasNonCompatibleSuperTrait(_) => {
|
||||||
|
HasNonCompatibleSuperTrait
|
||||||
|
}
|
||||||
});
|
});
|
||||||
ControlFlow::Continue(())
|
ControlFlow::Continue(())
|
||||||
});
|
});
|
||||||
assert_eq!(osvs, expected, "Object safety violations for `{name}` do not match;");
|
assert_eq!(osvs, expected, "Dyn Compatibility violations for `{name}` do not match;");
|
||||||
}
|
}
|
||||||
|
|
||||||
let remains: Vec<_> = expected.keys().collect();
|
let remains: Vec<_> = expected.keys().collect();
|
||||||
|
@ -73,7 +75,7 @@ fn check_object_safety<'a>(
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn item_bounds_can_reference_self() {
|
fn item_bounds_can_reference_self() {
|
||||||
check_object_safety(
|
check_dyn_compatibility(
|
||||||
r#"
|
r#"
|
||||||
//- minicore: eq
|
//- minicore: eq
|
||||||
pub trait Foo {
|
pub trait Foo {
|
||||||
|
@ -88,7 +90,7 @@ pub trait Foo {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn associated_consts() {
|
fn associated_consts() {
|
||||||
check_object_safety(
|
check_dyn_compatibility(
|
||||||
r#"
|
r#"
|
||||||
trait Bar {
|
trait Bar {
|
||||||
const X: usize;
|
const X: usize;
|
||||||
|
@ -100,7 +102,7 @@ trait Bar {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn bounds_reference_self() {
|
fn bounds_reference_self() {
|
||||||
check_object_safety(
|
check_dyn_compatibility(
|
||||||
r#"
|
r#"
|
||||||
//- minicore: eq
|
//- minicore: eq
|
||||||
trait X {
|
trait X {
|
||||||
|
@ -113,7 +115,7 @@ trait X {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn by_value_self() {
|
fn by_value_self() {
|
||||||
check_object_safety(
|
check_dyn_compatibility(
|
||||||
r#"
|
r#"
|
||||||
//- minicore: dispatch_from_dyn
|
//- minicore: dispatch_from_dyn
|
||||||
trait Bar {
|
trait Bar {
|
||||||
|
@ -135,7 +137,7 @@ trait Quux {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn generic_methods() {
|
fn generic_methods() {
|
||||||
check_object_safety(
|
check_dyn_compatibility(
|
||||||
r#"
|
r#"
|
||||||
//- minicore: dispatch_from_dyn
|
//- minicore: dispatch_from_dyn
|
||||||
trait Bar {
|
trait Bar {
|
||||||
|
@ -157,7 +159,7 @@ trait Qax {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn mentions_self() {
|
fn mentions_self() {
|
||||||
check_object_safety(
|
check_dyn_compatibility(
|
||||||
r#"
|
r#"
|
||||||
//- minicore: dispatch_from_dyn
|
//- minicore: dispatch_from_dyn
|
||||||
trait Bar {
|
trait Bar {
|
||||||
|
@ -182,7 +184,7 @@ trait Quux {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn no_static() {
|
fn no_static() {
|
||||||
check_object_safety(
|
check_dyn_compatibility(
|
||||||
r#"
|
r#"
|
||||||
//- minicore: dispatch_from_dyn
|
//- minicore: dispatch_from_dyn
|
||||||
trait Foo {
|
trait Foo {
|
||||||
|
@ -195,7 +197,7 @@ trait Foo {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn sized_self() {
|
fn sized_self() {
|
||||||
check_object_safety(
|
check_dyn_compatibility(
|
||||||
r#"
|
r#"
|
||||||
//- minicore: dispatch_from_dyn
|
//- minicore: dispatch_from_dyn
|
||||||
trait Bar: Sized {
|
trait Bar: Sized {
|
||||||
|
@ -205,7 +207,7 @@ trait Bar: Sized {
|
||||||
[("Bar", vec![SizedSelf])],
|
[("Bar", vec![SizedSelf])],
|
||||||
);
|
);
|
||||||
|
|
||||||
check_object_safety(
|
check_dyn_compatibility(
|
||||||
r#"
|
r#"
|
||||||
//- minicore: dispatch_from_dyn
|
//- minicore: dispatch_from_dyn
|
||||||
trait Bar
|
trait Bar
|
||||||
|
@ -220,7 +222,7 @@ trait Bar
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn supertrait_gat() {
|
fn supertrait_gat() {
|
||||||
check_object_safety(
|
check_dyn_compatibility(
|
||||||
r#"
|
r#"
|
||||||
//- minicore: dispatch_from_dyn
|
//- minicore: dispatch_from_dyn
|
||||||
trait GatTrait {
|
trait GatTrait {
|
||||||
|
@ -229,13 +231,13 @@ trait GatTrait {
|
||||||
|
|
||||||
trait SuperTrait<T>: GatTrait {}
|
trait SuperTrait<T>: GatTrait {}
|
||||||
"#,
|
"#,
|
||||||
[("GatTrait", vec![GAT]), ("SuperTrait", vec![HasNonSafeSuperTrait])],
|
[("GatTrait", vec![GAT]), ("SuperTrait", vec![HasNonCompatibleSuperTrait])],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn supertrait_mentions_self() {
|
fn supertrait_mentions_self() {
|
||||||
check_object_safety(
|
check_dyn_compatibility(
|
||||||
r#"
|
r#"
|
||||||
//- minicore: dispatch_from_dyn
|
//- minicore: dispatch_from_dyn
|
||||||
trait Bar<T> {
|
trait Bar<T> {
|
||||||
|
@ -251,7 +253,7 @@ trait Baz : Bar<Self> {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn rustc_issue_19538() {
|
fn rustc_issue_19538() {
|
||||||
check_object_safety(
|
check_dyn_compatibility(
|
||||||
r#"
|
r#"
|
||||||
//- minicore: dispatch_from_dyn
|
//- minicore: dispatch_from_dyn
|
||||||
trait Foo {
|
trait Foo {
|
||||||
|
@ -260,13 +262,13 @@ trait Foo {
|
||||||
|
|
||||||
trait Bar: Foo {}
|
trait Bar: Foo {}
|
||||||
"#,
|
"#,
|
||||||
[("Foo", vec![Method(Generic)]), ("Bar", vec![HasNonSafeSuperTrait])],
|
[("Foo", vec![Method(Generic)]), ("Bar", vec![HasNonCompatibleSuperTrait])],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn rustc_issue_22040() {
|
fn rustc_issue_22040() {
|
||||||
check_object_safety(
|
check_dyn_compatibility(
|
||||||
r#"
|
r#"
|
||||||
//- minicore: fmt, eq, dispatch_from_dyn
|
//- minicore: fmt, eq, dispatch_from_dyn
|
||||||
use core::fmt::Debug;
|
use core::fmt::Debug;
|
||||||
|
@ -281,7 +283,7 @@ trait Expr: Debug + PartialEq {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn rustc_issue_102762() {
|
fn rustc_issue_102762() {
|
||||||
check_object_safety(
|
check_dyn_compatibility(
|
||||||
r#"
|
r#"
|
||||||
//- minicore: future, send, sync, dispatch_from_dyn, deref
|
//- minicore: future, send, sync, dispatch_from_dyn, deref
|
||||||
use core::pin::Pin;
|
use core::pin::Pin;
|
||||||
|
@ -313,7 +315,7 @@ pub trait Fetcher: Send + Sync {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn rustc_issue_102933() {
|
fn rustc_issue_102933() {
|
||||||
check_object_safety(
|
check_dyn_compatibility(
|
||||||
r#"
|
r#"
|
||||||
//- minicore: future, dispatch_from_dyn, deref
|
//- minicore: future, dispatch_from_dyn, deref
|
||||||
use core::future::Future;
|
use core::future::Future;
|
||||||
|
@ -351,7 +353,7 @@ pub trait B2: Service<Response = i32> + B1 {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn rustc_issue_106247() {
|
fn rustc_issue_106247() {
|
||||||
check_object_safety(
|
check_dyn_compatibility(
|
||||||
r#"
|
r#"
|
||||||
//- minicore: sync, dispatch_from_dyn
|
//- minicore: sync, dispatch_from_dyn
|
||||||
pub trait Trait {
|
pub trait Trait {
|
||||||
|
@ -363,8 +365,8 @@ pub trait Trait {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn std_error_is_object_safe() {
|
fn std_error_is_dyn_compatible() {
|
||||||
check_object_safety(
|
check_dyn_compatibility(
|
||||||
r#"
|
r#"
|
||||||
//- minicore: fmt, dispatch_from_dyn
|
//- minicore: fmt, dispatch_from_dyn
|
||||||
trait Erased<'a>: 'a {}
|
trait Erased<'a>: 'a {}
|
||||||
|
@ -380,14 +382,14 @@ pub trait Error: core::fmt::Debug + core::fmt::Display {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn lifetime_gat_is_object_unsafe() {
|
fn lifetime_gat_is_dyn_incompatible() {
|
||||||
check_object_safety(
|
check_dyn_compatibility(
|
||||||
r#"
|
r#"
|
||||||
//- minicore: dispatch_from_dyn
|
//- minicore: dispatch_from_dyn
|
||||||
trait Foo {
|
trait Foo {
|
||||||
type Bar<'a>;
|
type Bar<'a>;
|
||||||
}
|
}
|
||||||
"#,
|
"#,
|
||||||
[("Foo", vec![ObjectSafetyViolationKind::GAT])],
|
[("Foo", vec![DynCompatibilityViolationKind::GAT])],
|
||||||
);
|
);
|
||||||
}
|
}
|
|
@ -38,11 +38,11 @@ pub mod consteval;
|
||||||
pub mod db;
|
pub mod db;
|
||||||
pub mod diagnostics;
|
pub mod diagnostics;
|
||||||
pub mod display;
|
pub mod display;
|
||||||
|
pub mod dyn_compatibility;
|
||||||
pub mod lang_items;
|
pub mod lang_items;
|
||||||
pub mod layout;
|
pub mod layout;
|
||||||
pub mod method_resolution;
|
pub mod method_resolution;
|
||||||
pub mod mir;
|
pub mod mir;
|
||||||
pub mod object_safety;
|
|
||||||
pub mod primitive;
|
pub mod primitive;
|
||||||
pub mod traits;
|
pub mod traits;
|
||||||
|
|
||||||
|
|
|
@ -144,9 +144,9 @@ pub use {
|
||||||
hir_ty::{
|
hir_ty::{
|
||||||
consteval::ConstEvalError,
|
consteval::ConstEvalError,
|
||||||
display::{ClosureStyle, HirDisplay, HirDisplayError, HirWrite},
|
display::{ClosureStyle, HirDisplay, HirDisplayError, HirWrite},
|
||||||
|
dyn_compatibility::{DynCompatibilityViolation, MethodViolationCode},
|
||||||
layout::LayoutError,
|
layout::LayoutError,
|
||||||
mir::{MirEvalError, MirLowerError},
|
mir::{MirEvalError, MirLowerError},
|
||||||
object_safety::{MethodViolationCode, ObjectSafetyViolation},
|
|
||||||
CastError, FnAbi, PointerCast, Safety,
|
CastError, FnAbi, PointerCast, Safety,
|
||||||
},
|
},
|
||||||
// FIXME: Properly encapsulate mir
|
// FIXME: Properly encapsulate mir
|
||||||
|
@ -2690,8 +2690,8 @@ impl Trait {
|
||||||
.count()
|
.count()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn object_safety(&self, db: &dyn HirDatabase) -> Option<ObjectSafetyViolation> {
|
pub fn dyn_compatibility(&self, db: &dyn HirDatabase) -> Option<DynCompatibilityViolation> {
|
||||||
hir_ty::object_safety::object_safety(db, self.id)
|
hir_ty::dyn_compatibility::dyn_compatibility(db, self.id)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn all_macro_calls(&self, db: &dyn HirDatabase) -> Box<[(AstId<ast::Item>, MacroCallId)]> {
|
fn all_macro_calls(&self, db: &dyn HirDatabase) -> Box<[(AstId<ast::Item>, MacroCallId)]> {
|
||||||
|
|
|
@ -7081,8 +7081,8 @@ This feature has no tracking issue, and is therefore likely internal to the comp
|
||||||
"##,
|
"##,
|
||||||
},
|
},
|
||||||
Lint {
|
Lint {
|
||||||
label: "object_safe_for_dispatch",
|
label: "dyn_compatible_for_dispatch",
|
||||||
description: r##"# `object_safe_for_dispatch`
|
description: r##"# `dyn_compatible_for_dispatch`
|
||||||
|
|
||||||
The tracking issue for this feature is: [#43561]
|
The tracking issue for this feature is: [#43561]
|
||||||
|
|
||||||
|
|
|
@ -3,9 +3,9 @@ use std::{mem, ops::Not};
|
||||||
|
|
||||||
use either::Either;
|
use either::Either;
|
||||||
use hir::{
|
use hir::{
|
||||||
db::ExpandDatabase, Adt, AsAssocItem, AsExternAssocItem, CaptureKind, HasCrate, HasSource,
|
db::ExpandDatabase, Adt, AsAssocItem, AsExternAssocItem, CaptureKind,
|
||||||
HirDisplay, Layout, LayoutError, MethodViolationCode, Name, ObjectSafetyViolation, Semantics,
|
DynCompatibilityViolation, HasCrate, HasSource, HirDisplay, Layout, LayoutError,
|
||||||
Trait, Type, TypeInfo,
|
MethodViolationCode, Name, Semantics, Trait, Type, TypeInfo,
|
||||||
};
|
};
|
||||||
use ide_db::{
|
use ide_db::{
|
||||||
base_db::SourceDatabase,
|
base_db::SourceDatabase,
|
||||||
|
@ -529,10 +529,10 @@ pub(super) fn definition(
|
||||||
_ => None,
|
_ => None,
|
||||||
};
|
};
|
||||||
|
|
||||||
let object_safety_info = if let Definition::Trait(it) = def {
|
let dyn_compatibility_info = if let Definition::Trait(it) = def {
|
||||||
let mut object_safety_info = String::new();
|
let mut dyn_compatibility_info = String::new();
|
||||||
render_object_safety(db, &mut object_safety_info, it.object_safety(db));
|
render_dyn_compatibility(db, &mut dyn_compatibility_info, it.dyn_compatibility(db));
|
||||||
Some(object_safety_info)
|
Some(dyn_compatibility_info)
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
@ -546,8 +546,8 @@ pub(super) fn definition(
|
||||||
desc.push_str(&layout_info);
|
desc.push_str(&layout_info);
|
||||||
desc.push('\n');
|
desc.push('\n');
|
||||||
}
|
}
|
||||||
if let Some(object_safety_info) = object_safety_info {
|
if let Some(dyn_compatibility_info) = dyn_compatibility_info {
|
||||||
desc.push_str(&object_safety_info);
|
desc.push_str(&dyn_compatibility_info);
|
||||||
desc.push('\n');
|
desc.push('\n');
|
||||||
}
|
}
|
||||||
desc.push_str(&label);
|
desc.push_str(&label);
|
||||||
|
@ -980,24 +980,24 @@ fn keyword_hints(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn render_object_safety(
|
fn render_dyn_compatibility(
|
||||||
db: &RootDatabase,
|
db: &RootDatabase,
|
||||||
buf: &mut String,
|
buf: &mut String,
|
||||||
safety: Option<ObjectSafetyViolation>,
|
safety: Option<DynCompatibilityViolation>,
|
||||||
) {
|
) {
|
||||||
let Some(osv) = safety else {
|
let Some(osv) = safety else {
|
||||||
buf.push_str("// Object Safety: Yes");
|
buf.push_str("// Dyn Compatible: Yes");
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
buf.push_str("// Object Safety: No\n// - Reason: ");
|
buf.push_str("// Dyn Compatible: No\n// - Reason: ");
|
||||||
match osv {
|
match osv {
|
||||||
ObjectSafetyViolation::SizedSelf => {
|
DynCompatibilityViolation::SizedSelf => {
|
||||||
buf.push_str("has a `Self: Sized` bound");
|
buf.push_str("has a `Self: Sized` bound");
|
||||||
}
|
}
|
||||||
ObjectSafetyViolation::SelfReferential => {
|
DynCompatibilityViolation::SelfReferential => {
|
||||||
buf.push_str("has a bound that references `Self`");
|
buf.push_str("has a bound that references `Self`");
|
||||||
}
|
}
|
||||||
ObjectSafetyViolation::Method(func, mvc) => {
|
DynCompatibilityViolation::Method(func, mvc) => {
|
||||||
let name = hir::Function::from(func).name(db);
|
let name = hir::Function::from(func).name(db);
|
||||||
format_to!(
|
format_to!(
|
||||||
buf,
|
buf,
|
||||||
|
@ -1020,7 +1020,7 @@ fn render_object_safety(
|
||||||
};
|
};
|
||||||
buf.push_str(desc);
|
buf.push_str(desc);
|
||||||
}
|
}
|
||||||
ObjectSafetyViolation::AssocConst(const_) => {
|
DynCompatibilityViolation::AssocConst(const_) => {
|
||||||
let name = hir::Const::from(const_).name(db);
|
let name = hir::Const::from(const_).name(db);
|
||||||
if let Some(name) = name {
|
if let Some(name) = name {
|
||||||
format_to!(buf, "has an associated constant `{}`", name.as_str());
|
format_to!(buf, "has an associated constant `{}`", name.as_str());
|
||||||
|
@ -1028,11 +1028,11 @@ fn render_object_safety(
|
||||||
buf.push_str("has an associated constant");
|
buf.push_str("has an associated constant");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ObjectSafetyViolation::GAT(alias) => {
|
DynCompatibilityViolation::GAT(alias) => {
|
||||||
let name = hir::TypeAlias::from(alias).name(db);
|
let name = hir::TypeAlias::from(alias).name(db);
|
||||||
format_to!(buf, "has a generic associated type `{}`", name.as_str());
|
format_to!(buf, "has a generic associated type `{}`", name.as_str());
|
||||||
}
|
}
|
||||||
ObjectSafetyViolation::HasNonSafeSuperTrait(super_trait) => {
|
DynCompatibilityViolation::HasNonCompatibleSuperTrait(super_trait) => {
|
||||||
let name = hir::Trait::from(super_trait).name(db);
|
let name = hir::Trait::from(super_trait).name(db);
|
||||||
format_to!(buf, "has a object unsafe supertrait `{}`", name.as_str());
|
format_to!(buf, "has a object unsafe supertrait `{}`", name.as_str());
|
||||||
}
|
}
|
||||||
|
|
|
@ -7175,7 +7175,7 @@ impl T$0 for () {}
|
||||||
```
|
```
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
// Object Safety: Yes
|
// Dyn Compatible: Yes
|
||||||
trait T {}
|
trait T {}
|
||||||
```
|
```
|
||||||
"#]],
|
"#]],
|
||||||
|
@ -7195,7 +7195,7 @@ impl T$0 for () {}
|
||||||
```
|
```
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
// Object Safety: Yes
|
// Dyn Compatible: Yes
|
||||||
trait T {}
|
trait T {}
|
||||||
```
|
```
|
||||||
"#]],
|
"#]],
|
||||||
|
@ -7219,7 +7219,7 @@ impl T$0 for () {}
|
||||||
```
|
```
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
// Object Safety: No
|
// Dyn Compatible: No
|
||||||
// - Reason: has a method `func` that is non dispatchable because of:
|
// - Reason: has a method `func` that is non dispatchable because of:
|
||||||
// - missing a receiver
|
// - missing a receiver
|
||||||
trait T { /* … */ }
|
trait T { /* … */ }
|
||||||
|
@ -7245,7 +7245,7 @@ impl T$0 for () {}
|
||||||
```
|
```
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
// Object Safety: No
|
// Dyn Compatible: No
|
||||||
// - Reason: has a method `func` that is non dispatchable because of:
|
// - Reason: has a method `func` that is non dispatchable because of:
|
||||||
// - missing a receiver
|
// - missing a receiver
|
||||||
trait T {
|
trait T {
|
||||||
|
@ -7275,7 +7275,7 @@ impl T$0 for () {}
|
||||||
```
|
```
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
// Object Safety: No
|
// Dyn Compatible: No
|
||||||
// - Reason: has a method `func` that is non dispatchable because of:
|
// - Reason: has a method `func` that is non dispatchable because of:
|
||||||
// - missing a receiver
|
// - missing a receiver
|
||||||
trait T {
|
trait T {
|
||||||
|
@ -7305,7 +7305,7 @@ impl T$0 for () {}
|
||||||
```
|
```
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
// Object Safety: No
|
// Dyn Compatible: No
|
||||||
// - Reason: has a method `func` that is non dispatchable because of:
|
// - Reason: has a method `func` that is non dispatchable because of:
|
||||||
// - missing a receiver
|
// - missing a receiver
|
||||||
trait T {
|
trait T {
|
||||||
|
|
|
@ -167,7 +167,7 @@ mod support {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn assert_ast_is_object_safe() {
|
fn assert_ast_is_dyn_compatible() {
|
||||||
fn _f(_: &dyn AstNode, _: &dyn HasName) {}
|
fn _f(_: &dyn AstNode, _: &dyn HasName) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
//! Object safe interface for file watching and reading.
|
//! Dynamically compatible interface for file watching and reading.
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
|
||||||
use paths::{AbsPath, AbsPathBuf};
|
use paths::{AbsPath, AbsPathBuf};
|
||||||
|
@ -232,6 +232,6 @@ impl fmt::Debug for Message {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn handle_is_object_safe() {
|
fn handle_is_dyn_compatible() {
|
||||||
fn _assert(_: &dyn Handle) {}
|
fn _assert(_: &dyn Handle) {}
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,7 +42,7 @@ The underlying engine makes sure that model is computed lazily (on-demand) and c
|
||||||
`crates/rust-analyzer/src/bin/main.rs` contains the main function which spawns LSP.
|
`crates/rust-analyzer/src/bin/main.rs` contains the main function which spawns LSP.
|
||||||
This is *the* entry point, but it front-loads a lot of complexity, so it's fine to just skim through it.
|
This is *the* entry point, but it front-loads a lot of complexity, so it's fine to just skim through it.
|
||||||
|
|
||||||
`crates/rust-analyzer/src/handlers.rs` implements all LSP requests and is a great place to start if you are already familiar with LSP.
|
`crates/rust-analyzer/src/handlers/requests.rs` implements all LSP requests and is a great place to start if you are already familiar with LSP.
|
||||||
|
|
||||||
`Analysis` and `AnalysisHost` types define the main API for consumers of IDE services.
|
`Analysis` and `AnalysisHost` types define the main API for consumers of IDE services.
|
||||||
|
|
||||||
|
|
|
@ -378,7 +378,7 @@ impl AstNode for AssocItem {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
Shared AST substructures are modeled via (object safe) traits:
|
Shared AST substructures are modeled via (dynamically compatible) traits:
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
trait HasVisibility: AstNode {
|
trait HasVisibility: AstNode {
|
||||||
|
|
|
@ -173,6 +173,8 @@ async function getDebugConfiguration(
|
||||||
if (debugConfig.name === "run binary") {
|
if (debugConfig.name === "run binary") {
|
||||||
// The LSP side: crates\rust-analyzer\src\main_loop\handlers.rs,
|
// The LSP side: crates\rust-analyzer\src\main_loop\handlers.rs,
|
||||||
// fn to_lsp_runnable(...) with RunnableKind::Bin
|
// fn to_lsp_runnable(...) with RunnableKind::Bin
|
||||||
|
// FIXME: Neither crates\rust-analyzer\src\main_loop\handlers.rs
|
||||||
|
// nor to_lsp_runnable exist anymore
|
||||||
debugConfig.name = `run ${path.basename(executable)}`;
|
debugConfig.name = `run ${path.basename(executable)}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -36,7 +36,7 @@ export async function selectRunnable(
|
||||||
|
|
||||||
if (runnables.length === 0) {
|
if (runnables.length === 0) {
|
||||||
// it is the debug case, run always has at least 'cargo check ...'
|
// it is the debug case, run always has at least 'cargo check ...'
|
||||||
// see crates\rust-analyzer\src\main_loop\handlers.rs, handle_runnables
|
// see crates\rust-analyzer\src\handlers\request.rs, handle_runnables
|
||||||
await vscode.window.showErrorMessage("There's no debug target!");
|
await vscode.window.showErrorMessage("There's no debug target!");
|
||||||
quickPick.dispose();
|
quickPick.dispose();
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -29,7 +29,7 @@ export class Cargo {
|
||||||
static artifactSpec(cargoArgs: string[], executableArgs?: string[]): ArtifactSpec {
|
static artifactSpec(cargoArgs: string[], executableArgs?: string[]): ArtifactSpec {
|
||||||
cargoArgs = [...cargoArgs, "--message-format=json"];
|
cargoArgs = [...cargoArgs, "--message-format=json"];
|
||||||
// arguments for a runnable from the quick pick should be updated.
|
// arguments for a runnable from the quick pick should be updated.
|
||||||
// see crates\rust-analyzer\src\main_loop\handlers.rs, handle_code_lens
|
// see crates\rust-analyzer\src\handlers\request.rs, handle_code_lens
|
||||||
switch (cargoArgs[0]) {
|
switch (cargoArgs[0]) {
|
||||||
case "run":
|
case "run":
|
||||||
cargoArgs[0] = "build";
|
cargoArgs[0] = "build";
|
||||||
|
|
Loading…
Reference in a new issue