Merge branch 'master' into sync-from-rust

This commit is contained in:
Laurențiu Nicola 2023-11-15 09:46:27 +02:00
commit 6b53c09ef5
73 changed files with 1252 additions and 401 deletions

View file

@ -34,7 +34,7 @@ pub mod symbols;
mod display;
use std::{iter, ops::ControlFlow};
use std::{iter, mem::discriminant, ops::ControlFlow};
use arrayvec::ArrayVec;
use base_db::{CrateDisplayName, CrateId, CrateOrigin, Edition, FileId, ProcMacroKind};
@ -54,14 +54,14 @@ use hir_def::{
resolver::{HasResolver, Resolver},
src::HasSource as _,
AssocItemId, AssocItemLoc, AttrDefId, ConstId, ConstParamId, CrateRootModuleId, DefWithBodyId,
EnumId, EnumVariantId, ExternCrateId, FunctionId, GenericDefId, HasModule, ImplId,
InTypeConstId, ItemContainerId, LifetimeParamId, LocalEnumVariantId, LocalFieldId, Lookup,
MacroExpander, MacroId, ModuleId, StaticId, StructId, TraitAliasId, TraitId, TypeAliasId,
TypeOrConstParamId, TypeParamId, UnionId,
EnumId, EnumVariantId, ExternCrateId, FunctionId, GenericDefId, GenericParamId, HasModule,
ImplId, InTypeConstId, ItemContainerId, LifetimeParamId, LocalEnumVariantId, LocalFieldId,
Lookup, MacroExpander, MacroId, ModuleId, StaticId, StructId, TraitAliasId, TraitId,
TypeAliasId, TypeOrConstParamId, TypeParamId, UnionId,
};
use hir_expand::{name::name, MacroCallKind};
use hir_ty::{
all_super_traits, autoderef,
all_super_traits, autoderef, check_orphan_rules,
consteval::{try_const_usize, unknown_const_as_generic, ConstEvalError, ConstExt},
diagnostics::BodyValidationDiagnostic,
known_const_to_ast,
@ -90,17 +90,7 @@ use crate::db::{DefDatabase, HirDatabase};
pub use crate::{
attrs::{resolve_doc_path_on, HasAttrs},
diagnostics::{
AnyDiagnostic, BreakOutsideOfLoop, CaseType, ExpectedFunction, InactiveCode,
IncoherentImpl, IncorrectCase, InvalidDeriveTarget, MacroDefError, MacroError,
MacroExpansionParseError, MalformedDerive, MismatchedArgCount,
MismatchedTupleStructPatArgCount, MissingFields, MissingMatchArms, MissingUnsafe,
MovedOutOfRef, NeedMut, NoSuchField, PrivateAssocItem, PrivateField,
ReplaceFilterMapNextWithFindMap, TypeMismatch, TypedHole, UndeclaredLabel,
UnimplementedBuiltinMacro, UnreachableLabel, UnresolvedExternCrate, UnresolvedField,
UnresolvedImport, UnresolvedMacroCall, UnresolvedMethodCall, UnresolvedModule,
UnresolvedProcMacro, UnusedMut, UnusedVariable,
},
diagnostics::*,
has_source::HasSource,
semantics::{PathResolution, Semantics, SemanticsScope, TypeInfo, VisibleTraits},
};
@ -604,6 +594,7 @@ impl Module {
let inherent_impls = db.inherent_impls_in_crate(self.id.krate());
let mut impl_assoc_items_scratch = vec![];
for impl_def in self.impl_defs(db) {
let loc = impl_def.id.lookup(db.upcast());
let tree = loc.id.item_tree(db.upcast());
@ -614,19 +605,109 @@ impl Module {
// FIXME: Once we diagnose the inputs to builtin derives, we should at least extract those diagnostics somehow
continue;
}
let ast_id_map = db.ast_id_map(file_id);
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 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 {
if !impl_def.check_orphan_rules(db) {
acc.push(TraitImplOrphan { impl_: ast_id_map.get(node.ast_id()), file_id }.into())
}
let trait_ = impl_def.trait_(db);
let trait_is_unsafe = trait_.map_or(false, |t| t.is_unsafe(db));
let impl_is_negative = impl_def.is_negative(db);
let impl_is_unsafe = impl_def.is_unsafe(db);
let drop_maybe_dangle = (|| {
// FIXME: This can be simplified a lot by exposing hir-ty's utils.rs::Generics helper
let trait_ = trait_?;
let drop_trait = db.lang_item(self.krate().into(), LangItem::Drop)?.as_trait()?;
if drop_trait != trait_.into() {
return None;
}
let parent = impl_def.id.into();
let generic_params = db.generic_params(parent);
let lifetime_params = generic_params.lifetimes.iter().map(|(local_id, _)| {
GenericParamId::LifetimeParamId(LifetimeParamId { parent, local_id })
});
let type_params = generic_params
.iter()
.filter(|(_, it)| it.type_param().is_some())
.map(|(local_id, _)| {
GenericParamId::TypeParamId(TypeParamId::from_unchecked(
TypeOrConstParamId { parent, local_id },
))
});
let res = type_params
.chain(lifetime_params)
.any(|p| db.attrs(AttrDefId::GenericParamId(p)).by_key("may_dangle").exists());
Some(res)
})()
.unwrap_or(false);
match (impl_is_unsafe, trait_is_unsafe, impl_is_negative, drop_maybe_dangle) {
// unsafe negative impl
(true, _, true, _) |
// unsafe impl for safe trait
(true, false, _, false) => acc.push(TraitImplIncorrectSafety { impl_: ast_id_map.get(node.ast_id()), file_id, should_be_safe: true }.into()),
// safe impl for unsafe trait
(false, true, false, _) |
// safe impl of dangling drop
(false, false, _, true) => acc.push(TraitImplIncorrectSafety { impl_: ast_id_map.get(node.ast_id()), file_id, should_be_safe: false }.into()),
_ => (),
};
if let Some(trait_) = trait_ {
let items = &db.trait_data(trait_.into()).items;
let required_items = items.iter().filter(|&(_, assoc)| match *assoc {
AssocItemId::FunctionId(it) => !db.function_data(it).has_body(),
AssocItemId::ConstId(_) => true,
AssocItemId::TypeAliasId(it) => db.type_alias_data(it).type_ref.is_none(),
});
impl_assoc_items_scratch.extend(db.impl_data(impl_def.id).items.iter().map(
|&item| {
(
item,
match item {
AssocItemId::FunctionId(it) => db.function_data(it).name.clone(),
AssocItemId::ConstId(it) => {
db.const_data(it).name.as_ref().unwrap().clone()
}
AssocItemId::TypeAliasId(it) => db.type_alias_data(it).name.clone(),
},
)
},
));
let missing: Vec<_> = required_items
.filter(|(name, id)| {
!impl_assoc_items_scratch.iter().any(|(impl_item, impl_name)| {
discriminant(impl_item) == discriminant(id) && impl_name == name
})
})
.map(|(name, item)| (name.clone(), AssocItem::from(*item)))
.collect();
if !missing.is_empty() {
acc.push(
TraitImplMissingAssocItems {
impl_: ast_id_map.get(node.ast_id()),
file_id,
missing,
}
.into(),
)
}
impl_assoc_items_scratch.clear();
}
for &item in &db.impl_data(impl_def.id).items {
let def: DefWithBody = match AssocItem::from(item) {
AssocItem::Function(it) => it.into(),
AssocItem::Const(it) => it.into(),
AssocItem::TypeAlias(_) => continue,
@ -665,8 +746,15 @@ impl Module {
db: &dyn DefDatabase,
item: impl Into<ItemInNs>,
prefer_no_std: bool,
prefer_prelude: bool,
) -> Option<ModPath> {
hir_def::find_path::find_path(db, item.into().into(), self.into(), prefer_no_std)
hir_def::find_path::find_path(
db,
item.into().into(),
self.into(),
prefer_no_std,
prefer_prelude,
)
}
/// Finds a path that can be used to refer to the given item from within
@ -677,6 +765,7 @@ impl Module {
item: impl Into<ItemInNs>,
prefix_kind: PrefixKind,
prefer_no_std: bool,
prefer_prelude: bool,
) -> Option<ModPath> {
hir_def::find_path::find_path_prefixed(
db,
@ -684,6 +773,7 @@ impl Module {
self.into(),
prefix_kind,
prefer_no_std,
prefer_prelude,
)
}
}
@ -3390,6 +3480,10 @@ impl Impl {
db.impl_data(self.id).is_negative
}
pub fn is_unsafe(self, db: &dyn HirDatabase) -> bool {
db.impl_data(self.id).is_unsafe
}
pub fn module(self, db: &dyn HirDatabase) -> Module {
self.id.lookup(db.upcast()).container.into()
}
@ -3398,6 +3492,10 @@ impl Impl {
let src = self.source(db)?;
src.file_id.as_builtin_derive_attr_node(db.upcast())
}
pub fn check_orphan_rules(self, db: &dyn HirDatabase) -> bool {
check_orphan_rules(db, self.id)
}
}
#[derive(Clone, PartialEq, Eq, Debug, Hash)]