Unnamed repository; edit this file 'description' to name the repository.
-rw-r--r--crates/hir-def/src/adt.rs19
-rw-r--r--crates/hir-def/src/data.rs33
-rw-r--r--crates/hir-def/src/nameres.rs10
-rw-r--r--crates/hir-def/src/nameres/collector.rs5
-rw-r--r--crates/hir-ty/src/chalk_ext.rs15
-rw-r--r--crates/hir-ty/src/diagnostics.rs6
-rw-r--r--crates/hir-ty/src/method_resolution.rs92
-rw-r--r--crates/hir-ty/src/tests/method_resolution.rs11
-rw-r--r--crates/hir-ty/src/tests/simple.rs60
-rw-r--r--crates/hir/src/diagnostics.rs5
-rw-r--r--crates/hir/src/lib.rs20
-rw-r--r--crates/ide-completion/src/completions/dot.rs6
-rw-r--r--crates/ide-completion/src/tests/pattern.rs1
-rw-r--r--crates/ide-completion/src/tests/special.rs1
-rw-r--r--crates/ide-diagnostics/src/handlers/incoherent_impl.rs77
-rw-r--r--crates/ide-diagnostics/src/lib.rs2
-rw-r--r--crates/ide/src/goto_implementation.rs1
-rw-r--r--crates/ide/src/inlay_hints/chaining.rs12
-rw-r--r--crates/test-utils/src/minicore.rs2
19 files changed, 305 insertions, 73 deletions
diff --git a/crates/hir-def/src/adt.rs b/crates/hir-def/src/adt.rs
index 9bc1c54a3c..b336f59ffe 100644
--- a/crates/hir-def/src/adt.rs
+++ b/crates/hir-def/src/adt.rs
@@ -40,6 +40,7 @@ pub struct StructData {
pub repr: Option<ReprOptions>,
pub visibility: RawVisibility,
pub rustc_has_incoherent_inherent_impls: bool,
+ pub fundamental: bool,
}
#[derive(Debug, Clone, PartialEq, Eq)]
@@ -173,10 +174,10 @@ impl StructData {
let item_tree = loc.id.item_tree(db);
let repr = repr_from_value(db, krate, &item_tree, ModItem::from(loc.id.value).into());
let cfg_options = db.crate_graph()[loc.container.krate].cfg_options.clone();
- let rustc_has_incoherent_inherent_impls = item_tree
- .attrs(db, loc.container.krate, ModItem::from(loc.id.value).into())
- .by_key("rustc_has_incoherent_inherent_impls")
- .exists();
+ let attrs = item_tree.attrs(db, loc.container.krate, ModItem::from(loc.id.value).into());
+ let rustc_has_incoherent_inherent_impls =
+ attrs.by_key("rustc_has_incoherent_inherent_impls").exists();
+ let fundamental = attrs.by_key("fundamental").exists();
let strukt = &item_tree[loc.id.value];
let (variant_data, diagnostics) = lower_fields(
@@ -196,6 +197,7 @@ impl StructData {
repr,
visibility: item_tree[strukt.visibility].clone(),
rustc_has_incoherent_inherent_impls,
+ fundamental,
}),
diagnostics.into(),
)
@@ -215,10 +217,10 @@ impl StructData {
let repr = repr_from_value(db, krate, &item_tree, ModItem::from(loc.id.value).into());
let cfg_options = db.crate_graph()[loc.container.krate].cfg_options.clone();
- let rustc_has_incoherent_inherent_impls = item_tree
- .attrs(db, loc.container.krate, ModItem::from(loc.id.value).into())
- .by_key("rustc_has_incoherent_inherent_impls")
- .exists();
+ let attrs = item_tree.attrs(db, loc.container.krate, ModItem::from(loc.id.value).into());
+ let rustc_has_incoherent_inherent_impls =
+ attrs.by_key("rustc_has_incoherent_inherent_impls").exists();
+ let fundamental = attrs.by_key("fundamental").exists();
let union = &item_tree[loc.id.value];
let (variant_data, diagnostics) = lower_fields(
@@ -238,6 +240,7 @@ impl StructData {
repr,
visibility: item_tree[union.visibility].clone(),
rustc_has_incoherent_inherent_impls,
+ fundamental,
}),
diagnostics.into(),
)
diff --git a/crates/hir-def/src/data.rs b/crates/hir-def/src/data.rs
index ee6e269fe5..1633a33bed 100644
--- a/crates/hir-def/src/data.rs
+++ b/crates/hir-def/src/data.rs
@@ -35,6 +35,7 @@ pub struct FunctionData {
pub visibility: RawVisibility,
pub abi: Option<Interned<str>>,
pub legacy_const_generics_indices: Box<[u32]>,
+ pub rustc_allow_incoherent_impl: bool,
flags: FnFlags,
}
@@ -84,13 +85,14 @@ impl FunctionData {
}
}
- let legacy_const_generics_indices = item_tree
- .attrs(db, krate, ModItem::from(loc.id.value).into())
+ let attrs = item_tree.attrs(db, krate, ModItem::from(loc.id.value).into());
+ let legacy_const_generics_indices = attrs
.by_key("rustc_legacy_const_generics")
.tt_values()
.next()
.map(parse_rustc_legacy_const_generics)
.unwrap_or_default();
+ let rustc_allow_incoherent_impl = attrs.by_key("rustc_allow_incoherent_impl").exists();
Arc::new(FunctionData {
name: func.name.clone(),
@@ -108,6 +110,7 @@ impl FunctionData {
abi: func.abi.clone(),
legacy_const_generics_indices,
flags,
+ rustc_allow_incoherent_impl,
})
}
@@ -171,6 +174,7 @@ pub struct TypeAliasData {
pub visibility: RawVisibility,
pub is_extern: bool,
pub rustc_has_incoherent_inherent_impls: bool,
+ pub rustc_allow_incoherent_impl: bool,
/// Bounds restricting the type alias itself (eg. `type Ty: Bound;` in a trait or impl).
pub bounds: Vec<Interned<TypeBound>>,
}
@@ -189,10 +193,14 @@ impl TypeAliasData {
item_tree[typ.visibility].clone()
};
- let rustc_has_incoherent_inherent_impls = item_tree
- .attrs(db, loc.container.module(db).krate(), ModItem::from(loc.id.value).into())
- .by_key("rustc_has_incoherent_inherent_impls")
- .exists();
+ let attrs = item_tree.attrs(
+ db,
+ loc.container.module(db).krate(),
+ ModItem::from(loc.id.value).into(),
+ );
+ let rustc_has_incoherent_inherent_impls =
+ attrs.by_key("rustc_has_incoherent_inherent_impls").exists();
+ let rustc_allow_incoherent_impl = attrs.by_key("rustc_allow_incoherent_impl").exists();
Arc::new(TypeAliasData {
name: typ.name.clone(),
@@ -200,6 +208,7 @@ impl TypeAliasData {
visibility,
is_extern: matches!(loc.container, ItemContainerId::ExternBlockId(_)),
rustc_has_incoherent_inherent_impls,
+ rustc_allow_incoherent_impl,
bounds: typ.bounds.to_vec(),
})
}
@@ -212,11 +221,12 @@ pub struct TraitData {
pub is_auto: bool,
pub is_unsafe: bool,
pub rustc_has_incoherent_inherent_impls: bool,
+ pub skip_array_during_method_dispatch: bool,
+ pub fundamental: bool,
pub visibility: RawVisibility,
/// Whether the trait has `#[rust_skip_array_during_method_dispatch]`. `hir_ty` will ignore
/// method calls to this trait's methods when the receiver is an array and the crate edition is
/// 2015 or 2018.
- pub skip_array_during_method_dispatch: bool,
// box it as the vec is usually empty anyways
pub attribute_calls: Option<Box<Vec<(AstId<ast::Item>, MacroCallId)>>>,
}
@@ -245,6 +255,7 @@ impl TraitData {
attrs.by_key("rustc_skip_array_during_method_dispatch").exists();
let rustc_has_incoherent_inherent_impls =
attrs.by_key("rustc_has_incoherent_inherent_impls").exists();
+ let fundamental = attrs.by_key("fundamental").exists();
let mut collector =
AssocItemCollector::new(db, module_id, tree_id.file_id(), ItemContainerId::TraitId(tr));
collector.collect(&item_tree, tree_id.tree_id(), &tr_def.items);
@@ -260,6 +271,7 @@ impl TraitData {
visibility,
skip_array_during_method_dispatch,
rustc_has_incoherent_inherent_impls,
+ fundamental,
}),
diagnostics.into(),
)
@@ -450,6 +462,7 @@ pub struct ConstData {
pub name: Option<Name>,
pub type_ref: Interned<TypeRef>,
pub visibility: RawVisibility,
+ pub rustc_allow_incoherent_impl: bool,
}
impl ConstData {
@@ -463,10 +476,16 @@ impl ConstData {
item_tree[konst.visibility].clone()
};
+ let rustc_allow_incoherent_impl = item_tree
+ .attrs(db, loc.container.module(db).krate(), ModItem::from(loc.id.value).into())
+ .by_key("rustc_allow_incoherent_impl")
+ .exists();
+
Arc::new(ConstData {
name: konst.name.clone(),
type_ref: konst.type_ref.clone(),
visibility,
+ rustc_allow_incoherent_impl,
})
}
}
diff --git a/crates/hir-def/src/nameres.rs b/crates/hir-def/src/nameres.rs
index 59b52c3caa..121b25c6c9 100644
--- a/crates/hir-def/src/nameres.rs
+++ b/crates/hir-def/src/nameres.rs
@@ -120,6 +120,8 @@ pub struct DefMap {
registered_tools: Vec<SmolStr>,
/// Unstable features of Rust enabled with `#![feature(A, B)]`.
unstable_features: FxHashSet<SmolStr>,
+ /// #[rustc_coherence_is_core]
+ rustc_coherence_is_core: bool,
edition: Edition,
recursion_limit: Option<u32>,
@@ -292,6 +294,7 @@ impl DefMap {
registered_tools: Vec::new(),
unstable_features: FxHashSet::default(),
diagnostics: Vec::new(),
+ rustc_coherence_is_core: false,
}
}
@@ -325,6 +328,10 @@ impl DefMap {
self.unstable_features.contains(feature)
}
+ pub fn is_rustc_coherence_is_core(&self) -> bool {
+ self.rustc_coherence_is_core
+ }
+
pub fn root(&self) -> LocalModuleId {
self.root
}
@@ -337,7 +344,7 @@ impl DefMap {
self.proc_macro_loading_error.as_deref()
}
- pub(crate) fn krate(&self) -> CrateId {
+ pub fn krate(&self) -> CrateId {
self.krate
}
@@ -502,6 +509,7 @@ impl DefMap {
krate: _,
prelude: _,
root: _,
+ rustc_coherence_is_core: _,
} = self;
extern_prelude.shrink_to_fit();
diff --git a/crates/hir-def/src/nameres/collector.rs b/crates/hir-def/src/nameres/collector.rs
index 6901930133..ddcee77ec4 100644
--- a/crates/hir-def/src/nameres/collector.rs
+++ b/crates/hir-def/src/nameres/collector.rs
@@ -296,6 +296,11 @@ impl DefCollector<'_> {
continue;
}
+ if attr_name.as_text().as_deref() == Some("rustc_coherence_is_core") {
+ self.def_map.rustc_coherence_is_core = true;
+ continue;
+ }
+
if *attr_name == hir_expand::name![feature] {
let features =
attr.parse_path_comma_token_tree().into_iter().flatten().filter_map(
diff --git a/crates/hir-ty/src/chalk_ext.rs b/crates/hir-ty/src/chalk_ext.rs
index e6aefbf271..2141894922 100644
--- a/crates/hir-ty/src/chalk_ext.rs
+++ b/crates/hir-ty/src/chalk_ext.rs
@@ -12,7 +12,7 @@ use hir_def::{
use crate::{
db::HirDatabase, from_assoc_type_id, from_chalk_trait_id, from_foreign_def_id,
from_placeholder_idx, to_chalk_trait_id, utils::generics, AdtId, AliasEq, AliasTy, Binders,
- CallableDefId, CallableSig, FnPointer, ImplTraitId, Interner, Lifetime, ProjectionTy,
+ CallableDefId, CallableSig, DynTy, FnPointer, ImplTraitId, Interner, Lifetime, ProjectionTy,
QuantifiedWhereClause, Substitution, TraitRef, Ty, TyBuilder, TyKind, TypeFlags, WhereClause,
};
@@ -378,6 +378,19 @@ impl ProjectionTyExt for ProjectionTy {
}
}
+pub trait DynTyExt {
+ fn principal(&self) -> Option<&TraitRef>;
+}
+
+impl DynTyExt for DynTy {
+ fn principal(&self) -> Option<&TraitRef> {
+ self.bounds.skip_binders().interned().get(0).and_then(|b| match b.skip_binders() {
+ crate::WhereClause::Implemented(trait_ref) => Some(trait_ref),
+ _ => None,
+ })
+ }
+}
+
pub trait TraitRefExt {
fn hir_trait_id(&self) -> TraitId;
}
diff --git a/crates/hir-ty/src/diagnostics.rs b/crates/hir-ty/src/diagnostics.rs
index 37eb06be1d..4b147b9970 100644
--- a/crates/hir-ty/src/diagnostics.rs
+++ b/crates/hir-ty/src/diagnostics.rs
@@ -11,3 +11,9 @@ pub use crate::diagnostics::{
},
unsafe_check::{missing_unsafe, unsafe_expressions, UnsafeExpr},
};
+
+#[derive(Debug, PartialEq, Eq)]
+pub struct IncoherentImpl {
+ pub file_id: hir_expand::HirFileId,
+ pub impl_: syntax::AstPtr<syntax::ast::Impl>,
+}
diff --git a/crates/hir-ty/src/method_resolution.rs b/crates/hir-ty/src/method_resolution.rs
index 92a17fc3a9..f3a27632bf 100644
--- a/crates/hir-ty/src/method_resolution.rs
+++ b/crates/hir-ty/src/method_resolution.rs
@@ -19,13 +19,13 @@ use stdx::never;
use crate::{
autoderef::{self, AutoderefKind},
db::HirDatabase,
- from_foreign_def_id,
+ from_chalk_trait_id, from_foreign_def_id,
infer::{unify::InferenceTable, Adjust, Adjustment, AutoBorrow, OverloadedDeref, PointerCast},
primitive::{FloatTy, IntTy, UintTy},
static_lifetime, to_chalk_trait_id,
utils::all_super_traits,
- AdtId, Canonical, CanonicalVarKinds, DebruijnIndex, ForeignDefId, InEnvironment, Interner,
- Scalar, Substitution, TraitEnvironment, TraitRef, TraitRefExt, Ty, TyBuilder, TyExt,
+ AdtId, Canonical, CanonicalVarKinds, DebruijnIndex, DynTyExt, ForeignDefId, InEnvironment,
+ Interner, Scalar, Substitution, TraitEnvironment, TraitRef, TraitRefExt, Ty, TyBuilder, TyExt,
};
/// This is used as a key for indexing impls.
@@ -266,11 +266,12 @@ impl TraitImpls {
#[derive(Debug, Eq, PartialEq)]
pub struct InherentImpls {
map: FxHashMap<TyFingerprint, Vec<ImplId>>,
+ invalid_impls: Vec<ImplId>,
}
impl InherentImpls {
pub(crate) fn inherent_impls_in_crate_query(db: &dyn HirDatabase, krate: CrateId) -> Arc<Self> {
- let mut impls = Self { map: FxHashMap::default() };
+ let mut impls = Self { map: FxHashMap::default(), invalid_impls: Vec::default() };
let crate_def_map = db.crate_def_map(krate);
impls.collect_def_map(db, &crate_def_map);
@@ -283,7 +284,7 @@ impl InherentImpls {
db: &dyn HirDatabase,
block: BlockId,
) -> Option<Arc<Self>> {
- let mut impls = Self { map: FxHashMap::default() };
+ let mut impls = Self { map: FxHashMap::default(), invalid_impls: Vec::default() };
if let Some(block_def_map) = db.block_def_map(block) {
impls.collect_def_map(db, &block_def_map);
impls.shrink_to_fit();
@@ -306,11 +307,17 @@ impl InherentImpls {
}
let self_ty = db.impl_self_ty(impl_id);
- let fp = TyFingerprint::for_inherent_impl(self_ty.skip_binders());
- if let Some(fp) = fp {
- self.map.entry(fp).or_default().push(impl_id);
+ let self_ty = self_ty.skip_binders();
+
+ match is_inherent_impl_coherent(db, def_map, &data, self_ty) {
+ true => {
+ // `fp` should only be `None` in error cases (either erroneous code or incomplete name resolution)
+ if let Some(fp) = TyFingerprint::for_inherent_impl(self_ty) {
+ self.map.entry(fp).or_default().push(impl_id);
+ }
+ }
+ false => self.invalid_impls.push(impl_id),
}
- // `fp` should only be `None` in error cases (either erroneous code or incomplete name resolution)
}
// To better support custom derives, collect impls in all unnamed const items.
@@ -334,6 +341,10 @@ impl InherentImpls {
pub fn all_impls(&self) -> impl Iterator<Item = ImplId> + '_ {
self.map.values().flat_map(|v| v.iter().copied())
}
+
+ pub fn invalid_impls(&self) -> &[ImplId] {
+ &self.invalid_impls
+ }
}
pub(crate) fn incoherent_inherent_impl_crates(
@@ -775,6 +786,69 @@ fn find_matching_impl(
}
}
+fn is_inherent_impl_coherent(
+ db: &dyn HirDatabase,
+ def_map: &DefMap,
+ impl_data: &ImplData,
+ self_ty: &Ty,
+) -> bool {
+ let self_ty = self_ty.kind(Interner);
+ let impl_allowed = match self_ty {
+ TyKind::Tuple(_, _)
+ | TyKind::FnDef(_, _)
+ | TyKind::Array(_, _)
+ | TyKind::Never
+ | TyKind::Raw(_, _)
+ | TyKind::Ref(_, _, _)
+ | TyKind::Slice(_)
+ | TyKind::Str
+ | TyKind::Scalar(_) => def_map.is_rustc_coherence_is_core(),
+
+ &TyKind::Adt(AdtId(adt), _) => adt.module(db.upcast()).krate() == def_map.krate(),
+ TyKind::Dyn(it) => it.principal().map_or(false, |trait_ref| {
+ from_chalk_trait_id(trait_ref.trait_id).module(db.upcast()).krate() == def_map.krate()
+ }),
+
+ _ => true,
+ };
+ impl_allowed || {
+ let rustc_has_incoherent_inherent_impls = match self_ty {
+ TyKind::Tuple(_, _)
+ | TyKind::FnDef(_, _)
+ | TyKind::Array(_, _)
+ | TyKind::Never
+ | TyKind::Raw(_, _)
+ | TyKind::Ref(_, _, _)
+ | TyKind::Slice(_)
+ | TyKind::Str
+ | TyKind::Scalar(_) => true,
+
+ &TyKind::Adt(AdtId(adt), _) => match adt {
+ hir_def::AdtId::StructId(it) => {
+ db.struct_data(it).rustc_has_incoherent_inherent_impls
+ }
+ hir_def::AdtId::UnionId(it) => {
+ db.union_data(it).rustc_has_incoherent_inherent_impls
+ }
+ hir_def::AdtId::EnumId(it) => db.enum_data(it).rustc_has_incoherent_inherent_impls,
+ },
+ TyKind::Dyn(it) => it.principal().map_or(false, |trait_ref| {
+ db.trait_data(from_chalk_trait_id(trait_ref.trait_id))
+ .rustc_has_incoherent_inherent_impls
+ }),
+
+ _ => false,
+ };
+ rustc_has_incoherent_inherent_impls
+ && !impl_data.items.is_empty()
+ && impl_data.items.iter().copied().all(|assoc| match assoc {
+ AssocItemId::FunctionId(it) => db.function_data(it).rustc_allow_incoherent_impl,
+ AssocItemId::ConstId(it) => db.const_data(it).rustc_allow_incoherent_impl,
+ AssocItemId::TypeAliasId(it) => db.type_alias_data(it).rustc_allow_incoherent_impl,
+ })
+ }
+}
+
pub fn iterate_path_candidates(
ty: &Canonical<Ty>,
db: &dyn HirDatabase,
diff --git a/crates/hir-ty/src/tests/method_resolution.rs b/crates/hir-ty/src/tests/method_resolution.rs
index e568e7013f..378d478336 100644
--- a/crates/hir-ty/src/tests/method_resolution.rs
+++ b/crates/hir-ty/src/tests/method_resolution.rs
@@ -9,6 +9,7 @@ fn infer_slice_method() {
check_types(
r#"
impl<T> [T] {
+ #[rustc_allow_incoherent_impl]
fn foo(&self) -> T {
loop {}
}
@@ -35,6 +36,7 @@ fn test() {
//- /lib.rs crate:other_crate
mod foo {
impl f32 {
+ #[rustc_allow_incoherent_impl]
pub fn foo(self) -> f32 { 0. }
}
}
@@ -47,6 +49,7 @@ fn infer_array_inherent_impl() {
check_types(
r#"
impl<T, const N: usize> [T; N] {
+ #[rustc_allow_incoherent_impl]
fn foo(&self) -> T {
loop {}
}
@@ -1437,6 +1440,7 @@ fn resolve_const_generic_array_methods() {
r#"
#[lang = "array"]
impl<T, const N: usize> [T; N] {
+ #[rustc_allow_incoherent_impl]
pub fn map<F, U>(self, f: F) -> [U; N]
where
F: FnMut(T) -> U,
@@ -1445,6 +1449,7 @@ impl<T, const N: usize> [T; N] {
#[lang = "slice"]
impl<T> [T] {
+ #[rustc_allow_incoherent_impl]
pub fn map<F, U>(self, f: F) -> &[U]
where
F: FnMut(T) -> U,
@@ -1468,6 +1473,7 @@ struct Const<const N: usize>;
#[lang = "array"]
impl<T, const N: usize> [T; N] {
+ #[rustc_allow_incoherent_impl]
pub fn my_map<F, U, const X: usize>(self, f: F, c: Const<X>) -> [U; X]
where
F: FnMut(T) -> U,
@@ -1476,6 +1482,7 @@ impl<T, const N: usize> [T; N] {
#[lang = "slice"]
impl<T> [T] {
+ #[rustc_allow_incoherent_impl]
pub fn my_map<F, const X: usize, U>(self, f: F, c: Const<X>) -> &[U]
where
F: FnMut(T) -> U,
@@ -1874,14 +1881,14 @@ fn incoherent_impls() {
pub struct Box<T>(T);
use core::error::Error;
-#[rustc_allow_incoherent_impl]
impl dyn Error {
+ #[rustc_allow_incoherent_impl]
pub fn downcast<T: Error + 'static>(self: Box<Self>) -> Result<Box<T>, Box<dyn Error>> {
loop {}
}
}
-#[rustc_allow_incoherent_impl]
impl dyn Error + Send {
+ #[rustc_allow_incoherent_impl]
/// Attempts to downcast the box to a concrete type.
pub fn downcast<T: Error + 'static>(self: Box<Self>) -> Result<Box<T>, Box<dyn Error + Send>> {
let err: Box<dyn Error> = self;
diff --git a/crates/hir-ty/src/tests/simple.rs b/crates/hir-ty/src/tests/simple.rs
index 0e9c349afe..13cc3fea52 100644
--- a/crates/hir-ty/src/tests/simple.rs
+++ b/crates/hir-ty/src/tests/simple.rs
@@ -1116,21 +1116,22 @@ fn infer_inherent_method() {
fn infer_inherent_method_str() {
check_infer(
r#"
- #[lang = "str"]
- impl str {
- fn foo(&self) -> i32 {}
- }
+#![rustc_coherence_is_core]
+#[lang = "str"]
+impl str {
+ fn foo(&self) -> i32 {}
+}
- fn test() {
- "foo".foo();
- }
- "#,
+fn test() {
+ "foo".foo();
+}
+"#,
expect![[r#"
- 39..43 'self': &str
- 52..54 '{}': i32
- 68..88 '{ ...o(); }': ()
- 74..79 '"foo"': &str
- 74..85 '"foo".foo()': i32
+ 67..71 'self': &str
+ 80..82 '{}': i32
+ 96..116 '{ ...o(); }': ()
+ 102..107 '"foo"': &str
+ 102..113 '"foo".foo()': i32
"#]],
);
}
@@ -2640,6 +2641,7 @@ impl<T> [T] {}
#[lang = "slice_alloc"]
impl<T> [T] {
+ #[rustc_allow_incoherent_impl]
pub fn into_vec<A: Allocator>(self: Box<Self, A>) -> Vec<T, A> {
unimplemented!()
}
@@ -2655,22 +2657,22 @@ struct Astruct;
impl B for Astruct {}
"#,
expect![[r#"
- 569..573 'self': Box<[T], A>
- 602..634 '{ ... }': Vec<T, A>
- 648..761 '{ ...t]); }': ()
- 658..661 'vec': Vec<i32, Global>
- 664..679 '<[_]>::into_vec': fn into_vec<i32, Global>(Box<[i32], Global>) -> Vec<i32, Global>
- 664..691 '<[_]>:...1i32])': Vec<i32, Global>
- 680..690 'box [1i32]': Box<[i32; 1], Global>
- 684..690 '[1i32]': [i32; 1]
- 685..689 '1i32': i32
- 701..702 'v': Vec<Box<dyn B, Global>, Global>
- 722..739 '<[_]> ...to_vec': fn into_vec<Box<dyn B, Global>, Global>(Box<[Box<dyn B, Global>], Global>) -> Vec<Box<dyn B, Global>, Global>
- 722..758 '<[_]> ...ruct])': Vec<Box<dyn B, Global>, Global>
- 740..757 'box [b...truct]': Box<[Box<dyn B, Global>; 1], Global>
- 744..757 '[box Astruct]': [Box<dyn B, Global>; 1]
- 745..756 'box Astruct': Box<Astruct, Global>
- 749..756 'Astruct': Astruct
+ 604..608 'self': Box<[T], A>
+ 637..669 '{ ... }': Vec<T, A>
+ 683..796 '{ ...t]); }': ()
+ 693..696 'vec': Vec<i32, Global>
+ 699..714 '<[_]>::into_vec': fn into_vec<i32, Global>(Box<[i32], Global>) -> Vec<i32, Global>
+ 699..726 '<[_]>:...1i32])': Vec<i32, Global>
+ 715..725 'box [1i32]': Box<[i32; 1], Global>
+ 719..725 '[1i32]': [i32; 1]
+ 720..724 '1i32': i32
+ 736..737 'v': Vec<Box<dyn B, Global>, Global>
+ 757..774 '<[_]> ...to_vec': fn into_vec<Box<dyn B, Global>, Global>(Box<[Box<dyn B, Global>], Global>) -> Vec<Box<dyn B, Global>, Global>
+ 757..793 '<[_]> ...ruct])': Vec<Box<dyn B, Global>, Global>
+ 775..792 'box [b...truct]': Box<[Box<dyn B, Global>; 1], Global>
+ 779..792 '[box Astruct]': [Box<dyn B, Global>; 1]
+ 780..791 'box Astruct': Box<Astruct, Global>
+ 784..791 'Astruct': Astruct
"#]],
)
}
diff --git a/crates/hir/src/diagnostics.rs b/crates/hir/src/diagnostics.rs
index 8f019a81b2..253d62dafc 100644
--- a/crates/hir/src/diagnostics.rs
+++ b/crates/hir/src/diagnostics.rs
@@ -3,6 +3,8 @@
//!
//! This probably isn't the best way to do this -- ideally, diagnostics should
//! be expressed in terms of hir types themselves.
+pub use hir_ty::diagnostics::{IncoherentImpl, IncorrectCase};
+
use base_db::CrateId;
use cfg::{CfgExpr, CfgOptions};
use either::Either;
@@ -35,6 +37,7 @@ diagnostics![
InactiveCode,
IncorrectCase,
InvalidDeriveTarget,
+ IncoherentImpl,
MacroError,
MalformedDerive,
MismatchedArgCount,
@@ -220,5 +223,3 @@ pub struct NeedMut {
pub struct UnusedMut {
pub local: Local,
}
-
-pub use hir_ty::diagnostics::IncorrectCase;
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs
index 27c4577d60..35424feec8 100644
--- a/crates/hir/src/lib.rs
+++ b/crates/hir/src/lib.rs
@@ -85,10 +85,10 @@ use crate::db::{DefDatabase, HirDatabase};
pub use crate::{
attrs::{HasAttrs, Namespace},
diagnostics::{
- AnyDiagnostic, BreakOutsideOfLoop, ExpectedFunction, InactiveCode, IncorrectCase,
- InvalidDeriveTarget, MacroError, MalformedDerive, MismatchedArgCount, MissingFields,
- MissingMatchArms, MissingUnsafe, NeedMut, NoSuchField, PrivateAssocItem, PrivateField,
- ReplaceFilterMapNextWithFindMap, TypeMismatch, UnimplementedBuiltinMacro,
+ AnyDiagnostic, BreakOutsideOfLoop, ExpectedFunction, InactiveCode, IncoherentImpl,
+ IncorrectCase, InvalidDeriveTarget, MacroError, MalformedDerive, MismatchedArgCount,
+ MissingFields, MissingMatchArms, MissingUnsafe, NeedMut, NoSuchField, PrivateAssocItem,
+ PrivateField, ReplaceFilterMapNextWithFindMap, TypeMismatch, UnimplementedBuiltinMacro,
UnresolvedExternCrate, UnresolvedField, UnresolvedImport, UnresolvedMacroCall,
UnresolvedMethodCall, UnresolvedModule, UnresolvedProcMacro, UnusedMut,
},
@@ -604,11 +604,23 @@ impl Module {
}
}
+ let inherent_impls = db.inherent_impls_in_crate(self.id.krate());
+
for impl_def in self.impl_defs(db) {
for diag in db.impl_data_with_diagnostics(impl_def.id).1.iter() {
emit_def_diagnostic(db, acc, diag);
}
+ if inherent_impls.invalid_impls().contains(&impl_def.id) {
+ let loc = impl_def.id.lookup(db.upcast());
+ let tree = loc.id.item_tree(db.upcast());
+ let node = &tree[loc.id.value];
+ let file_id = loc.id.file_id();
+ let ast_id_map = db.ast_id_map(file_id);
+
+ acc.push(IncoherentImpl { impl_: ast_id_map.get(node.ast_id()), file_id }.into())
+ }
+
for item in impl_def.items(db) {
let def: DefWithBody = match item {
AssocItem::Function(it) => it.into(),
diff --git a/crates/ide-completion/src/completions/dot.rs b/crates/ide-completion/src/completions/dot.rs
index 09ac57153a..77246379e7 100644
--- a/crates/ide-completion/src/completions/dot.rs
+++ b/crates/ide-completion/src/completions/dot.rs
@@ -415,7 +415,6 @@ fn foo(a: lib::A) { a.$0 }
fn test_local_impls() {
check(
r#"
-//- /lib.rs crate:lib
pub struct A {}
mod m {
impl super::A {
@@ -427,9 +426,8 @@ mod m {
}
}
}
-//- /main.rs crate:main deps:lib
-fn foo(a: lib::A) {
- impl lib::A {
+fn foo(a: A) {
+ impl A {
fn local_method(&self) {}
}
a.$0
diff --git a/crates/ide-completion/src/tests/pattern.rs b/crates/ide-completion/src/tests/pattern.rs
index ad9254e7f2..c0e485c36f 100644
--- a/crates/ide-completion/src/tests/pattern.rs
+++ b/crates/ide-completion/src/tests/pattern.rs
@@ -614,6 +614,7 @@ fn f(u: U) {
check_empty(
r#"
+#![rustc_coherence_is_core]
#[lang = "u32"]
impl u32 {
pub const MIN: Self = 0;
diff --git a/crates/ide-completion/src/tests/special.rs b/crates/ide-completion/src/tests/special.rs
index cb71c7b2bd..f8a6f6cd3e 100644
--- a/crates/ide-completion/src/tests/special.rs
+++ b/crates/ide-completion/src/tests/special.rs
@@ -608,6 +608,7 @@ fn f() {
}
//- /core.rs crate:core
+#![rustc_coherence_is_core]
#[lang = "u8"]
impl u8 {
pub const MAX: Self = 255;
diff --git a/crates/ide-diagnostics/src/handlers/incoherent_impl.rs b/crates/ide-diagnostics/src/handlers/incoherent_impl.rs
new file mode 100644
index 0000000000..72af9ebfcb
--- /dev/null
+++ b/crates/ide-diagnostics/src/handlers/incoherent_impl.rs
@@ -0,0 +1,77 @@
+use hir::InFile;
+
+use crate::{Diagnostic, DiagnosticsContext, Severity};
+
+// Diagnostic: incoherent-impl
+//
+// This diagnostic is triggered if the targe type of an impl is from a foreign crate.
+pub(crate) fn incoherent_impl(ctx: &DiagnosticsContext<'_>, d: &hir::IncoherentImpl) -> Diagnostic {
+ Diagnostic::new(
+ "incoherent-impl",
+ format!("cannot define inherent `impl` for foreign type"),
+ ctx.sema.diagnostics_display_range(InFile::new(d.file_id, d.impl_.clone().into())).range,
+ )
+ .severity(Severity::Error)
+}
+
+#[cfg(test)]
+mod change_case {
+ use crate::tests::check_diagnostics;
+
+ #[test]
+ fn primitive() {
+ check_diagnostics(
+ r#"
+ impl bool {}
+//^^^^^^^^^^^^ error: cannot define inherent `impl` for foreign type
+"#,
+ );
+ }
+
+ #[test]
+ fn primitive_rustc_allow_incoherent_impl() {
+ check_diagnostics(
+ r#"
+impl bool {
+ #[rustc_allow_incoherent_impl]
+ fn falsch(self) -> Self { false }
+}
+"#,
+ );
+ }
+
+ #[test]
+ fn rustc_allow_incoherent_impl() {
+ check_diagnostics(
+ r#"
+//- /lib.rs crate:foo
+#[rustc_has_incoherent_inherent_impls]
+pub struct S;
+//- /main.rs crate:main deps:foo
+impl foo::S {
+ #[rustc_allow_incoherent_impl]
+ fn func(self) {}
+}
+"#,
+ );
+ check_diagnostics(
+ r#"
+//- /lib.rs crate:foo
+pub struct S;
+//- /main.rs crate:main deps:foo
+ impl foo::S { #[rustc_allow_incoherent_impl] fn func(self) {} }
+//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: cannot define inherent `impl` for foreign type
+"#,
+ );
+ check_diagnostics(
+ r#"
+//- /lib.rs crate:foo
+#[rustc_has_incoherent_inherent_impls]
+pub struct S;
+//- /main.rs crate:main deps:foo
+ impl foo::S { fn func(self) {} }
+//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: cannot define inherent `impl` for foreign type
+"#,
+ );
+ }
+}
diff --git a/crates/ide-diagnostics/src/lib.rs b/crates/ide-diagnostics/src/lib.rs
index f6c9b79c30..71f136b8c9 100644
--- a/crates/ide-diagnostics/src/lib.rs
+++ b/crates/ide-diagnostics/src/lib.rs
@@ -29,6 +29,7 @@ mod handlers {
pub(crate) mod break_outside_of_loop;
pub(crate) mod expected_function;
pub(crate) mod inactive_code;
+ pub(crate) mod incoherent_impl;
pub(crate) mod incorrect_case;
pub(crate) mod invalid_derive_target;
pub(crate) mod macro_error;
@@ -254,6 +255,7 @@ pub fn diagnostics(
AnyDiagnostic::BreakOutsideOfLoop(d) => handlers::break_outside_of_loop::break_outside_of_loop(&ctx, &d),
AnyDiagnostic::ExpectedFunction(d) => handlers::expected_function::expected_function(&ctx, &d),
AnyDiagnostic::IncorrectCase(d) => handlers::incorrect_case::incorrect_case(&ctx, &d),
+ AnyDiagnostic::IncoherentImpl(d) => handlers::incoherent_impl::incoherent_impl(&ctx, &d),
AnyDiagnostic::MacroError(d) => handlers::macro_error::macro_error(&ctx, &d),
AnyDiagnostic::MalformedDerive(d) => handlers::malformed_derive::malformed_derive(&ctx, &d),
AnyDiagnostic::MismatchedArgCount(d) => handlers::mismatched_arg_count::mismatched_arg_count(&ctx, &d),
diff --git a/crates/ide/src/goto_implementation.rs b/crates/ide/src/goto_implementation.rs
index 190ab80ba0..a1a119629a 100644
--- a/crates/ide/src/goto_implementation.rs
+++ b/crates/ide/src/goto_implementation.rs
@@ -297,6 +297,7 @@ impl Foo<str> {}
//- /lib.rs crate:main deps:core
fn foo(_: bool$0) {{}}
//- /libcore.rs crate:core
+#![rustc_coherence_is_core]
#[lang = "bool"]
impl bool {}
//^^^^
diff --git a/crates/ide/src/inlay_hints/chaining.rs b/crates/ide/src/inlay_hints/chaining.rs
index 0a7513e465..1e1771259b 100644
--- a/crates/ide/src/inlay_hints/chaining.rs
+++ b/crates/ide/src/inlay_hints/chaining.rs
@@ -435,7 +435,7 @@ fn main() {
file_id: FileId(
1,
),
- range: 3386..3394,
+ range: 3415..3423,
},
),
tooltip: "",
@@ -448,7 +448,7 @@ fn main() {
file_id: FileId(
1,
),
- range: 3418..3422,
+ range: 3447..3451,
},
),
tooltip: "",
@@ -468,7 +468,7 @@ fn main() {
file_id: FileId(
1,
),
- range: 3386..3394,
+ range: 3415..3423,
},
),
tooltip: "",
@@ -481,7 +481,7 @@ fn main() {
file_id: FileId(
1,
),
- range: 3418..3422,
+ range: 3447..3451,
},
),
tooltip: "",
@@ -501,7 +501,7 @@ fn main() {
file_id: FileId(
1,
),
- range: 3386..3394,
+ range: 3415..3423,
},
),
tooltip: "",
@@ -514,7 +514,7 @@ fn main() {
file_id: FileId(
1,
),
- range: 3418..3422,
+ range: 3447..3451,
},
),
tooltip: "",
diff --git a/crates/test-utils/src/minicore.rs b/crates/test-utils/src/minicore.rs
index 93ff76a040..ca6de4061a 100644
--- a/crates/test-utils/src/minicore.rs
+++ b/crates/test-utils/src/minicore.rs
@@ -44,6 +44,8 @@
//! try: infallible
//! unsize: sized
+#![rustc_coherence_is_core]
+
pub mod marker {
// region:sized
#[lang = "sized"]