mirror of
https://github.com/rust-lang/rust.git
synced 2026-04-27 18:57:42 +03:00
Auto merge of #150702 - lnicola:sync-from-ra, r=lnicola
`rust-analyzer` subtree update Subtree update of `rust-analyzer` to https://github.com/rust-lang/rust-analyzer/commit/6a1246b69ca761480b9278df019f717b549cface. Created using https://github.com/rust-lang/josh-sync. r? `@ghost`
This commit is contained in:
@@ -26,6 +26,9 @@ pub struct EditionedFileIdData {
|
||||
krate: Crate,
|
||||
}
|
||||
|
||||
// FIXME: This poses an invalidation problem, if one constructs an `EditionedFileId` with a
|
||||
// different crate then whatever the input of a memo used, it will invalidate the memo causing
|
||||
// it to recompute even if the crate is not really used.
|
||||
/// We like to include the origin crate in an `EditionedFileId` (for use in the item tree),
|
||||
/// but this poses us a problem.
|
||||
///
|
||||
|
||||
@@ -57,8 +57,7 @@ pub fn new(mut ctx: span::SyntaxContext) -> Self {
|
||||
Self(ctx)
|
||||
}
|
||||
|
||||
// FIXME: Inline this
|
||||
pub(crate) fn lookup(self) -> SyntaxContext {
|
||||
pub(crate) fn syntax_context(self) -> SyntaxContext {
|
||||
self.0
|
||||
}
|
||||
|
||||
@@ -73,7 +72,8 @@ pub(crate) fn is_root(self) -> bool {
|
||||
pub type PatPtr = AstPtr<ast::Pat>;
|
||||
pub type PatSource = InFile<PatPtr>;
|
||||
|
||||
pub type LabelPtr = AstPtr<ast::Label>;
|
||||
/// BlockExpr -> Desugared label from try block
|
||||
pub type LabelPtr = AstPtr<Either<ast::Label, ast::BlockExpr>>;
|
||||
pub type LabelSource = InFile<LabelPtr>;
|
||||
|
||||
pub type FieldPtr = AstPtr<ast::RecordExprField>;
|
||||
@@ -942,7 +942,7 @@ pub fn patterns_for_binding(&self, binding: BindingId) -> &[PatId] {
|
||||
}
|
||||
|
||||
pub fn node_label(&self, node: InFile<&ast::Label>) -> Option<LabelId> {
|
||||
let src = node.map(AstPtr::new);
|
||||
let src = node.map(AstPtr::new).map(AstPtr::wrap_left);
|
||||
self.expr_only()?.label_map.get(&src).cloned()
|
||||
}
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
ExpandError, ExpandErrorKind, ExpandResult, HirFileId, InFile, Lookup, MacroCallId,
|
||||
eager::EagerCallBackFn, mod_path::ModPath, span_map::SpanMap,
|
||||
};
|
||||
use span::{AstIdMap, Edition, SyntaxContext};
|
||||
use span::{AstIdMap, SyntaxContext};
|
||||
use syntax::ast::HasAttrs;
|
||||
use syntax::{AstNode, Parse, ast};
|
||||
use triomphe::Arc;
|
||||
@@ -75,11 +75,6 @@ pub(super) fn is_cfg_enabled(
|
||||
AttrFlags::is_cfg_enabled_for(owner, cfg_options)
|
||||
}
|
||||
|
||||
pub(super) fn call_syntax_ctx(&self) -> SyntaxContext {
|
||||
// FIXME:
|
||||
SyntaxContext::root(Edition::CURRENT_FIXME)
|
||||
}
|
||||
|
||||
pub(super) fn enter_expand<T: ast::AstNode>(
|
||||
&mut self,
|
||||
db: &dyn DefDatabase,
|
||||
|
||||
@@ -1096,7 +1096,7 @@ fn maybe_collect_expr(&mut self, expr: ast::Expr) -> Option<ExprId> {
|
||||
ast::Expr::WhileExpr(e) => self.collect_while_loop(syntax_ptr, e),
|
||||
ast::Expr::ForExpr(e) => self.collect_for_loop(syntax_ptr, e),
|
||||
ast::Expr::CallExpr(e) => {
|
||||
// FIXME: Remove this once we drop support for <1.86, https://github.com/rust-lang/rust/commit/ac9cb908ac4301dfc25e7a2edee574320022ae2c
|
||||
// FIXME(MINIMUM_SUPPORTED_TOOLCHAIN_VERSION): Remove this once we drop support for <1.86, https://github.com/rust-lang/rust/commit/ac9cb908ac4301dfc25e7a2edee574320022ae2c
|
||||
let is_rustc_box = {
|
||||
let attrs = e.attrs();
|
||||
attrs.filter_map(|it| it.as_simple_atom()).any(|it| it == "rustc_box")
|
||||
@@ -1649,7 +1649,7 @@ fn with_binding_owner(&mut self, create_expr: impl FnOnce(&mut Self) -> ExprId)
|
||||
fn desugar_try_block(&mut self, e: BlockExpr) -> ExprId {
|
||||
let try_from_output = self.lang_path(self.lang_items().TryTraitFromOutput);
|
||||
let label = self.generate_new_name();
|
||||
let label = self.alloc_label_desugared(Label { name: label });
|
||||
let label = self.alloc_label_desugared(Label { name: label }, AstPtr::new(&e).wrap_right());
|
||||
let old_label = self.current_try_block_label.replace(label);
|
||||
|
||||
let ptr = AstPtr::new(&e).upcast();
|
||||
@@ -2319,7 +2319,6 @@ fn collect_pat(&mut self, pat: ast::Pat, binding_list: &mut BindingList) -> PatI
|
||||
ast::Pat::SlicePat(p) => {
|
||||
let SlicePatComponents { prefix, slice, suffix } = p.components();
|
||||
|
||||
// FIXME properly handle `RestPat`
|
||||
Pat::Slice {
|
||||
prefix: prefix.into_iter().map(|p| self.collect_pat(p, binding_list)).collect(),
|
||||
slice: slice.map(|p| self.collect_pat(p, binding_list)),
|
||||
@@ -2399,7 +2398,6 @@ fn collect_pat(&mut self, pat: ast::Pat, binding_list: &mut BindingList) -> PatI
|
||||
};
|
||||
let start = range_part_lower(p.start());
|
||||
let end = range_part_lower(p.end());
|
||||
// FIXME: Exclusive ended pattern range is stabilised
|
||||
match p.op_kind() {
|
||||
Some(range_type) => Pat::Range { start, end, range_type },
|
||||
None => Pat::Missing,
|
||||
@@ -2519,9 +2517,9 @@ fn resolve_label(
|
||||
let mut hygiene_info = if hygiene_id.is_root() {
|
||||
None
|
||||
} else {
|
||||
hygiene_id.lookup().outer_expn(self.db).map(|expansion| {
|
||||
hygiene_id.syntax_context().outer_expn(self.db).map(|expansion| {
|
||||
let expansion = self.db.lookup_intern_macro_call(expansion.into());
|
||||
(hygiene_id.lookup().parent(self.db), expansion.def)
|
||||
(hygiene_id.syntax_context().parent(self.db), expansion.def)
|
||||
})
|
||||
};
|
||||
let name = Name::new_lifetime(&lifetime.text());
|
||||
@@ -2727,17 +2725,17 @@ fn missing_pat(&mut self) -> PatId {
|
||||
self.store.pats.alloc(Pat::Missing)
|
||||
}
|
||||
|
||||
fn alloc_label(&mut self, label: Label, ptr: LabelPtr) -> LabelId {
|
||||
fn alloc_label(&mut self, label: Label, ptr: AstPtr<ast::Label>) -> LabelId {
|
||||
self.alloc_label_desugared(label, ptr.wrap_left())
|
||||
}
|
||||
|
||||
fn alloc_label_desugared(&mut self, label: Label, ptr: LabelPtr) -> LabelId {
|
||||
let src = self.expander.in_file(ptr);
|
||||
let id = self.store.labels.alloc(label);
|
||||
self.store.label_map_back.insert(id, src);
|
||||
self.store.label_map.insert(src, id);
|
||||
id
|
||||
}
|
||||
// FIXME: desugared labels don't have ptr, that's wrong and should be fixed somehow.
|
||||
fn alloc_label_desugared(&mut self, label: Label) -> LabelId {
|
||||
self.store.labels.alloc(label)
|
||||
}
|
||||
|
||||
fn is_lowering_awaitable_block(&self) -> &Awaitable {
|
||||
self.awaitable_context.as_ref().unwrap_or(&Awaitable::No("unknown"))
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
use base_db::FxIndexSet;
|
||||
use hir_expand::name::Name;
|
||||
use intern::{Symbol, sym};
|
||||
use span::SyntaxContext;
|
||||
use syntax::{AstPtr, AstToken as _, ast};
|
||||
|
||||
use crate::{
|
||||
@@ -49,7 +50,7 @@ pub(super) fn collect_format_args(
|
||||
self.expand_macros_to_string(template.clone()).map(|it| (it, template))
|
||||
}) {
|
||||
Some(((s, is_direct_literal), template)) => {
|
||||
let call_ctx = self.expander.call_syntax_ctx();
|
||||
let call_ctx = SyntaxContext::root(self.def_map.edition());
|
||||
let hygiene = self.hygiene_id_for(s.syntax().text_range());
|
||||
let fmt = format_args::parse(
|
||||
&s,
|
||||
|
||||
@@ -20,8 +20,7 @@
|
||||
/// Data about a generic type parameter (to a function, struct, impl, ...).
|
||||
#[derive(Clone, PartialEq, Eq, Debug, Hash)]
|
||||
pub struct TypeParamData {
|
||||
/// [`None`] only if the type ref is an [`crate::type_ref::TypeRef::ImplTrait`]. FIXME: Might be better to just
|
||||
/// make it always be a value, giving impl trait a special name.
|
||||
/// [`None`] only if the type ref is an [`crate::type_ref::TypeRef::ImplTrait`].
|
||||
pub name: Option<Name>,
|
||||
pub default: Option<TypeRefId>,
|
||||
pub provenance: TypeParamProvenance,
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
//! HIR for references to types. Paths in these are not yet resolved. They can
|
||||
//! be directly created from an ast::TypeRef, without further queries.
|
||||
|
||||
use std::fmt::Write;
|
||||
|
||||
use hir_expand::name::Name;
|
||||
use intern::Symbol;
|
||||
use la_arena::Idx;
|
||||
@@ -10,12 +8,11 @@
|
||||
|
||||
use crate::{
|
||||
LifetimeParamId, TypeParamId,
|
||||
builtin_type::{BuiltinInt, BuiltinType, BuiltinUint},
|
||||
expr_store::{
|
||||
ExpressionStore,
|
||||
path::{GenericArg, Path},
|
||||
},
|
||||
hir::{ExprId, Literal},
|
||||
hir::ExprId,
|
||||
};
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
|
||||
@@ -275,56 +272,3 @@ pub fn as_path<'a>(&self, map: &'a ExpressionStore) -> Option<(&'a Path, TraitBo
|
||||
pub struct ConstRef {
|
||||
pub expr: ExprId,
|
||||
}
|
||||
|
||||
/// A literal constant value
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||
pub enum LiteralConstRef {
|
||||
Int(i128),
|
||||
UInt(u128),
|
||||
Bool(bool),
|
||||
Char(char),
|
||||
|
||||
/// Case of an unknown value that rustc might know but we don't
|
||||
// FIXME: this is a hack to get around chalk not being able to represent unevaluatable
|
||||
// constants
|
||||
// https://github.com/rust-lang/rust-analyzer/pull/8813#issuecomment-840679177
|
||||
// https://rust-lang.zulipchat.com/#narrow/stream/144729-wg-traits/topic/Handling.20non.20evaluatable.20constants'.20equality/near/238386348
|
||||
Unknown,
|
||||
}
|
||||
|
||||
impl LiteralConstRef {
|
||||
pub fn builtin_type(&self) -> BuiltinType {
|
||||
match self {
|
||||
LiteralConstRef::UInt(_) | LiteralConstRef::Unknown => {
|
||||
BuiltinType::Uint(BuiltinUint::U128)
|
||||
}
|
||||
LiteralConstRef::Int(_) => BuiltinType::Int(BuiltinInt::I128),
|
||||
LiteralConstRef::Char(_) => BuiltinType::Char,
|
||||
LiteralConstRef::Bool(_) => BuiltinType::Bool,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Literal> for LiteralConstRef {
|
||||
fn from(literal: Literal) -> Self {
|
||||
match literal {
|
||||
Literal::Char(c) => Self::Char(c),
|
||||
Literal::Bool(flag) => Self::Bool(flag),
|
||||
Literal::Int(num, _) => Self::Int(num),
|
||||
Literal::Uint(num, _) => Self::UInt(num),
|
||||
_ => Self::Unknown,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Display for LiteralConstRef {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
|
||||
match self {
|
||||
LiteralConstRef::Int(num) => num.fmt(f),
|
||||
LiteralConstRef::UInt(num) => num.fmt(f),
|
||||
LiteralConstRef::Bool(flag) => flag.fmt(f),
|
||||
LiteralConstRef::Char(c) => write!(f, "'{c}'"),
|
||||
LiteralConstRef::Unknown => f.write_char('_'),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -158,7 +158,7 @@ pub struct ItemScope {
|
||||
/// declared.
|
||||
declarations: ThinVec<ModuleDefId>,
|
||||
|
||||
impls: ThinVec<ImplId>,
|
||||
impls: ThinVec<(ImplId, /* trait impl */ bool)>,
|
||||
builtin_derive_impls: ThinVec<BuiltinDeriveImplId>,
|
||||
extern_blocks: ThinVec<ExternBlockId>,
|
||||
unnamed_consts: ThinVec<ConstId>,
|
||||
@@ -327,7 +327,15 @@ pub fn use_decls(&self) -> impl ExactSizeIterator<Item = UseId> + '_ {
|
||||
}
|
||||
|
||||
pub fn impls(&self) -> impl ExactSizeIterator<Item = ImplId> + '_ {
|
||||
self.impls.iter().copied()
|
||||
self.impls.iter().map(|&(id, _)| id)
|
||||
}
|
||||
|
||||
pub fn trait_impls(&self) -> impl Iterator<Item = ImplId> + '_ {
|
||||
self.impls.iter().filter(|&&(_, is_trait_impl)| is_trait_impl).map(|&(id, _)| id)
|
||||
}
|
||||
|
||||
pub fn inherent_impls(&self) -> impl Iterator<Item = ImplId> + '_ {
|
||||
self.impls.iter().filter(|&&(_, is_trait_impl)| !is_trait_impl).map(|&(id, _)| id)
|
||||
}
|
||||
|
||||
pub fn builtin_derive_impls(&self) -> impl ExactSizeIterator<Item = BuiltinDeriveImplId> + '_ {
|
||||
@@ -472,8 +480,8 @@ pub(crate) fn get_legacy_macro(&self, name: &Name) -> Option<&[MacroId]> {
|
||||
self.legacy_macros.get(name).map(|it| &**it)
|
||||
}
|
||||
|
||||
pub(crate) fn define_impl(&mut self, imp: ImplId) {
|
||||
self.impls.push(imp);
|
||||
pub(crate) fn define_impl(&mut self, imp: ImplId, is_trait_impl: bool) {
|
||||
self.impls.push((imp, is_trait_impl));
|
||||
}
|
||||
|
||||
pub(crate) fn define_builtin_derive_impl(&mut self, imp: BuiltinDeriveImplId) {
|
||||
|
||||
@@ -614,7 +614,9 @@ pub struct Trait {
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Eq, PartialEq)]
|
||||
pub struct Impl {}
|
||||
pub struct Impl {
|
||||
pub is_trait_impl: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct TypeAlias {
|
||||
|
||||
@@ -271,7 +271,7 @@ fn lower_impl(&mut self, impl_def: &ast::Impl) -> ItemTreeAstId<Impl> {
|
||||
let ast_id = self.source_ast_id_map.ast_id(impl_def);
|
||||
// Note that trait impls don't get implicit `Self` unlike traits, because here they are a
|
||||
// type alias rather than a type parameter, so this is handled by the resolver.
|
||||
let res = Impl {};
|
||||
let res = Impl { is_trait_impl: impl_def.trait_().is_some() };
|
||||
self.tree.small_data.insert(ast_id.upcast(), SmallModItem::Impl(res));
|
||||
ast_id
|
||||
}
|
||||
|
||||
@@ -258,7 +258,7 @@ fn print_mod_item(&mut self, item: ModItemId) {
|
||||
w!(self, "trait {} {{ ... }}", name.display(self.db, self.edition));
|
||||
}
|
||||
ModItemId::Impl(ast_id) => {
|
||||
let Impl {} = &self.tree[ast_id];
|
||||
let Impl { is_trait_impl: _ } = &self.tree[ast_id];
|
||||
self.print_ast_id(ast_id.erase());
|
||||
w!(self, "impl {{ ... }}");
|
||||
}
|
||||
|
||||
@@ -40,8 +40,12 @@ pub fn crate_lang_items(db: &dyn DefDatabase, krate: Crate) -> Option<Box<LangIt
|
||||
|
||||
let crate_def_map = crate_def_map(db, krate);
|
||||
|
||||
if !crate_def_map.is_unstable_feature_enabled(&sym::lang_items) {
|
||||
return None;
|
||||
}
|
||||
|
||||
for (_, module_data) in crate_def_map.modules() {
|
||||
for impl_def in module_data.scope.impls() {
|
||||
for impl_def in module_data.scope.inherent_impls() {
|
||||
lang_items.collect_lang_item(db, impl_def);
|
||||
for &(_, assoc) in impl_def.impl_items(db).items.iter() {
|
||||
match assoc {
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
use std::{any::TypeId, iter, ops::Range, sync};
|
||||
|
||||
use base_db::{RootQueryDb, SourceDatabase};
|
||||
use base_db::RootQueryDb;
|
||||
use expect_test::Expect;
|
||||
use hir_expand::{
|
||||
AstId, ExpansionInfo, InFile, MacroCallId, MacroCallKind, MacroKind,
|
||||
@@ -387,7 +387,7 @@ fn pretty_print_macro_expansion(
|
||||
impl ProcMacroExpander for IdentityWhenValidProcMacroExpander {
|
||||
fn expand(
|
||||
&self,
|
||||
_: &dyn SourceDatabase,
|
||||
_: &dyn ExpandDatabase,
|
||||
subtree: &TopSubtree,
|
||||
_: Option<&TopSubtree>,
|
||||
_: &base_db::Env,
|
||||
|
||||
@@ -2028,7 +2028,9 @@ fn collect(&mut self, items: &[ModItemId], container: ItemContainerId) {
|
||||
let impl_id =
|
||||
ImplLoc { container: module_id, id: InFile::new(self.file_id(), imp) }
|
||||
.intern(db);
|
||||
self.def_collector.def_map.modules[self.module_id].scope.define_impl(impl_id)
|
||||
self.def_collector.def_map.modules[self.module_id]
|
||||
.scope
|
||||
.define_impl(impl_id, self.item_tree[imp].is_trait_impl)
|
||||
}
|
||||
ModItemId::Function(id) => {
|
||||
let it = &self.item_tree[id];
|
||||
|
||||
@@ -267,7 +267,6 @@ pub(super) fn resolve_path_fp_with_macro_single(
|
||||
// plain import or absolute path in 2015: crate-relative with
|
||||
// fallback to extern prelude (with the simplification in
|
||||
// rust-lang/rust#57745)
|
||||
// FIXME there must be a nicer way to write this condition
|
||||
PathKind::Plain | PathKind::Abs
|
||||
if self.data.edition == Edition::Edition2015
|
||||
&& (path.kind == PathKind::Abs || mode == ResolveMode::Import) =>
|
||||
@@ -383,7 +382,6 @@ pub(super) fn resolve_path_fp_in_all_preludes(
|
||||
// plain import or absolute path in 2015: crate-relative with
|
||||
// fallback to extern prelude (with the simplification in
|
||||
// rust-lang/rust#57745)
|
||||
// FIXME there must be a nicer way to write this condition
|
||||
PathKind::Plain | PathKind::Abs
|
||||
if self.data.edition == Edition::Edition2015
|
||||
&& (path.kind == PathKind::Abs || mode == ResolveMode::Import) =>
|
||||
|
||||
@@ -950,7 +950,7 @@ fn hygiene_info(
|
||||
hygiene_id: HygieneId,
|
||||
) -> Option<(SyntaxContext, MacroDefId)> {
|
||||
if !hygiene_id.is_root() {
|
||||
let ctx = hygiene_id.lookup();
|
||||
let ctx = hygiene_id.syntax_context();
|
||||
ctx.outer_expn(db).map(|expansion| {
|
||||
let expansion = db.lookup_intern_macro_call(expansion.into());
|
||||
(ctx.parent(db), expansion.def)
|
||||
|
||||
@@ -9,8 +9,8 @@
|
||||
|
||||
use crate::{
|
||||
AstId, BuiltinAttrExpander, BuiltinDeriveExpander, BuiltinFnLikeExpander, EagerCallInfo,
|
||||
EagerExpander, EditionedFileId, ExpandError, ExpandResult, ExpandTo, HirFileId, MacroCallId,
|
||||
MacroCallKind, MacroCallLoc, MacroDefId, MacroDefKind,
|
||||
EagerExpander, EditionedFileId, ExpandError, ExpandResult, ExpandTo, FileRange, HirFileId,
|
||||
MacroCallId, MacroCallKind, MacroCallLoc, MacroDefId, MacroDefKind,
|
||||
attrs::Meta,
|
||||
builtin::pseudo_derive_attr_expansion,
|
||||
cfg_process::attr_macro_input_to_token_tree,
|
||||
@@ -61,6 +61,9 @@ pub trait ExpandDatabase: RootQueryDb {
|
||||
#[salsa::lru(1024)]
|
||||
fn ast_id_map(&self, file_id: HirFileId) -> Arc<AstIdMap>;
|
||||
|
||||
#[salsa::transparent]
|
||||
fn resolve_span(&self, span: Span) -> FileRange;
|
||||
|
||||
#[salsa::transparent]
|
||||
fn parse_or_expand(&self, file_id: HirFileId) -> SyntaxNode;
|
||||
|
||||
@@ -158,6 +161,13 @@ fn syntax_context(db: &dyn ExpandDatabase, file: HirFileId, edition: Edition) ->
|
||||
}
|
||||
}
|
||||
|
||||
fn resolve_span(db: &dyn ExpandDatabase, Span { range, anchor, ctx: _ }: Span) -> FileRange {
|
||||
let file_id = EditionedFileId::from_span_guess_origin(db, anchor.file_id);
|
||||
let anchor_offset =
|
||||
db.ast_id_map(file_id.into()).get_erased(anchor.ast_id).text_range().start();
|
||||
FileRange { file_id, range: range + anchor_offset }
|
||||
}
|
||||
|
||||
/// This expands the given macro call, but with different arguments. This is
|
||||
/// used for completion, where we want to see what 'would happen' if we insert a
|
||||
/// token. The `token_to_map` mapped down into the expansion, with the mapped
|
||||
|
||||
@@ -901,11 +901,8 @@ pub fn map_range_up_once(
|
||||
let span = self.exp_map.span_at(token.start());
|
||||
match &self.arg_map {
|
||||
SpanMap::RealSpanMap(_) => {
|
||||
let file_id =
|
||||
EditionedFileId::from_span_guess_origin(db, span.anchor.file_id).into();
|
||||
let anchor_offset =
|
||||
db.ast_id_map(file_id).get_erased(span.anchor.ast_id).text_range().start();
|
||||
InFile { file_id, value: smallvec::smallvec![span.range + anchor_offset] }
|
||||
let range = db.resolve_span(span);
|
||||
InFile { file_id: range.file_id.into(), value: smallvec::smallvec![range.range] }
|
||||
}
|
||||
SpanMap::ExpansionSpanMap(arg_map) => {
|
||||
let Some(arg_node) = &self.arg.value else {
|
||||
@@ -947,7 +944,7 @@ pub fn map_node_range_up_rooted(
|
||||
range: TextRange,
|
||||
) -> Option<FileRange> {
|
||||
let mut spans = exp_map.spans_for_range(range).filter(|span| span.ctx.is_root());
|
||||
let Span { range, anchor, ctx: _ } = spans.next()?;
|
||||
let Span { range, anchor, ctx } = spans.next()?;
|
||||
let mut start = range.start();
|
||||
let mut end = range.end();
|
||||
|
||||
@@ -958,10 +955,7 @@ pub fn map_node_range_up_rooted(
|
||||
start = start.min(span.range.start());
|
||||
end = end.max(span.range.end());
|
||||
}
|
||||
let file_id = EditionedFileId::from_span_guess_origin(db, anchor.file_id);
|
||||
let anchor_offset =
|
||||
db.ast_id_map(file_id.into()).get_erased(anchor.ast_id).text_range().start();
|
||||
Some(FileRange { file_id, range: TextRange::new(start, end) + anchor_offset })
|
||||
Some(db.resolve_span(Span { range: TextRange::new(start, end), anchor, ctx }))
|
||||
}
|
||||
|
||||
/// Maps up the text range out of the expansion hierarchy back into the original file its from.
|
||||
@@ -984,10 +978,7 @@ pub fn map_node_range_up(
|
||||
start = start.min(span.range.start());
|
||||
end = end.max(span.range.end());
|
||||
}
|
||||
let file_id = EditionedFileId::from_span_guess_origin(db, anchor.file_id);
|
||||
let anchor_offset =
|
||||
db.ast_id_map(file_id.into()).get_erased(anchor.ast_id).text_range().start();
|
||||
Some((FileRange { file_id, range: TextRange::new(start, end) + anchor_offset }, ctx))
|
||||
Some((db.resolve_span(Span { range: TextRange::new(start, end), anchor, ctx }), ctx))
|
||||
}
|
||||
|
||||
/// Looks up the span at the given offset.
|
||||
@@ -997,10 +988,7 @@ pub fn span_for_offset(
|
||||
offset: TextSize,
|
||||
) -> (FileRange, SyntaxContext) {
|
||||
let span = exp_map.span_at(offset);
|
||||
let file_id = EditionedFileId::from_span_guess_origin(db, span.anchor.file_id);
|
||||
let anchor_offset =
|
||||
db.ast_id_map(file_id.into()).get_erased(span.anchor.ast_id).text_range().start();
|
||||
(FileRange { file_id, range: span.range + anchor_offset }, span.ctx)
|
||||
(db.resolve_span(span), span.ctx)
|
||||
}
|
||||
|
||||
/// In Rust, macros expand token trees to token trees. When we want to turn a
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
use std::any::Any;
|
||||
use std::{panic::RefUnwindSafe, sync};
|
||||
|
||||
use base_db::{Crate, CrateBuilderId, CratesIdMap, Env, ProcMacroLoadingError, SourceDatabase};
|
||||
use base_db::{Crate, CrateBuilderId, CratesIdMap, Env, ProcMacroLoadingError};
|
||||
use intern::Symbol;
|
||||
use rustc_hash::FxHashMap;
|
||||
use span::Span;
|
||||
@@ -25,7 +25,7 @@ pub trait ProcMacroExpander: fmt::Debug + Send + Sync + RefUnwindSafe + Any {
|
||||
/// [`ProcMacroKind::Attr`]), environment variables, and span information.
|
||||
fn expand(
|
||||
&self,
|
||||
db: &dyn SourceDatabase,
|
||||
db: &dyn ExpandDatabase,
|
||||
subtree: &tt::TopSubtree,
|
||||
attrs: Option<&tt::TopSubtree>,
|
||||
env: &Env,
|
||||
|
||||
@@ -7,9 +7,9 @@
|
||||
use hir_def::{
|
||||
ConstId, EnumVariantId, GeneralConstId, HasModule, StaticId,
|
||||
attrs::AttrFlags,
|
||||
builtin_type::{BuiltinInt, BuiltinType, BuiltinUint},
|
||||
expr_store::Body,
|
||||
hir::{Expr, ExprId},
|
||||
type_ref::LiteralConstRef,
|
||||
hir::{Expr, ExprId, Literal},
|
||||
};
|
||||
use hir_expand::Lookup;
|
||||
use rustc_type_ir::inherent::IntoKind;
|
||||
@@ -23,7 +23,7 @@
|
||||
mir::{MirEvalError, MirLowerError},
|
||||
next_solver::{
|
||||
Const, ConstBytes, ConstKind, DbInterner, ErrorGuaranteed, GenericArg, GenericArgs,
|
||||
ParamEnv, StoredConst, StoredGenericArgs, Ty, ValueConst,
|
||||
StoredConst, StoredGenericArgs, Ty, ValueConst,
|
||||
},
|
||||
traits::StoredParamEnvAndCrate,
|
||||
};
|
||||
@@ -81,47 +81,122 @@ fn from(value: MirEvalError) -> Self {
|
||||
/// Interns a constant scalar with the given type
|
||||
pub fn intern_const_ref<'a>(
|
||||
db: &'a dyn HirDatabase,
|
||||
value: &LiteralConstRef,
|
||||
value: &Literal,
|
||||
ty: Ty<'a>,
|
||||
krate: Crate,
|
||||
_krate: Crate,
|
||||
) -> Const<'a> {
|
||||
let interner = DbInterner::new_no_crate(db);
|
||||
let layout = db
|
||||
.layout_of_ty(ty.store(), ParamEnvAndCrate { param_env: ParamEnv::empty(), krate }.store());
|
||||
let kind = match value {
|
||||
LiteralConstRef::Int(i) => {
|
||||
// FIXME: We should handle failure of layout better.
|
||||
let size = layout.map(|it| it.size.bytes_usize()).unwrap_or(16);
|
||||
&Literal::Uint(i, builtin_ty)
|
||||
if builtin_ty.is_none() || ty.as_builtin() == builtin_ty.map(BuiltinType::Uint) =>
|
||||
{
|
||||
let memory = match ty.as_builtin() {
|
||||
Some(BuiltinType::Uint(builtin_uint)) => match builtin_uint {
|
||||
BuiltinUint::U8 => Box::new([i as u8]) as Box<[u8]>,
|
||||
BuiltinUint::U16 => Box::new((i as u16).to_le_bytes()),
|
||||
BuiltinUint::U32 => Box::new((i as u32).to_le_bytes()),
|
||||
BuiltinUint::U64 => Box::new((i as u64).to_le_bytes()),
|
||||
BuiltinUint::U128 => Box::new((i).to_le_bytes()),
|
||||
BuiltinUint::Usize => Box::new((i as usize).to_le_bytes()),
|
||||
},
|
||||
_ => return Const::new(interner, rustc_type_ir::ConstKind::Error(ErrorGuaranteed)),
|
||||
};
|
||||
rustc_type_ir::ConstKind::Value(ValueConst::new(
|
||||
ty,
|
||||
ConstBytes {
|
||||
memory: i.to_le_bytes()[0..size].into(),
|
||||
memory_map: MemoryMap::default(),
|
||||
},
|
||||
ConstBytes { memory, memory_map: MemoryMap::default() },
|
||||
))
|
||||
}
|
||||
LiteralConstRef::UInt(i) => {
|
||||
let size = layout.map(|it| it.size.bytes_usize()).unwrap_or(16);
|
||||
&Literal::Int(i, None)
|
||||
if ty
|
||||
.as_builtin()
|
||||
.is_some_and(|builtin_ty| matches!(builtin_ty, BuiltinType::Uint(_))) =>
|
||||
{
|
||||
let memory = match ty.as_builtin() {
|
||||
Some(BuiltinType::Uint(builtin_uint)) => match builtin_uint {
|
||||
BuiltinUint::U8 => Box::new([i as u8]) as Box<[u8]>,
|
||||
BuiltinUint::U16 => Box::new((i as u16).to_le_bytes()),
|
||||
BuiltinUint::U32 => Box::new((i as u32).to_le_bytes()),
|
||||
BuiltinUint::U64 => Box::new((i as u64).to_le_bytes()),
|
||||
BuiltinUint::U128 => Box::new((i as u128).to_le_bytes()),
|
||||
BuiltinUint::Usize => Box::new((i as usize).to_le_bytes()),
|
||||
},
|
||||
_ => return Const::new(interner, rustc_type_ir::ConstKind::Error(ErrorGuaranteed)),
|
||||
};
|
||||
rustc_type_ir::ConstKind::Value(ValueConst::new(
|
||||
ty,
|
||||
ConstBytes {
|
||||
memory: i.to_le_bytes()[0..size].into(),
|
||||
memory_map: MemoryMap::default(),
|
||||
},
|
||||
ConstBytes { memory, memory_map: MemoryMap::default() },
|
||||
))
|
||||
}
|
||||
LiteralConstRef::Bool(b) => rustc_type_ir::ConstKind::Value(ValueConst::new(
|
||||
&Literal::Int(i, builtin_ty)
|
||||
if builtin_ty.is_none() || ty.as_builtin() == builtin_ty.map(BuiltinType::Int) =>
|
||||
{
|
||||
let memory = match ty.as_builtin() {
|
||||
Some(BuiltinType::Int(builtin_int)) => match builtin_int {
|
||||
BuiltinInt::I8 => Box::new([i as u8]) as Box<[u8]>,
|
||||
BuiltinInt::I16 => Box::new((i as i16).to_le_bytes()),
|
||||
BuiltinInt::I32 => Box::new((i as i32).to_le_bytes()),
|
||||
BuiltinInt::I64 => Box::new((i as i64).to_le_bytes()),
|
||||
BuiltinInt::I128 => Box::new((i).to_le_bytes()),
|
||||
BuiltinInt::Isize => Box::new((i as isize).to_le_bytes()),
|
||||
},
|
||||
_ => return Const::new(interner, rustc_type_ir::ConstKind::Error(ErrorGuaranteed)),
|
||||
};
|
||||
rustc_type_ir::ConstKind::Value(ValueConst::new(
|
||||
ty,
|
||||
ConstBytes { memory, memory_map: MemoryMap::default() },
|
||||
))
|
||||
}
|
||||
Literal::Float(float_type_wrapper, builtin_float)
|
||||
if builtin_float.is_none()
|
||||
|| ty.as_builtin() == builtin_float.map(BuiltinType::Float) =>
|
||||
{
|
||||
let memory = match ty.as_builtin().unwrap() {
|
||||
BuiltinType::Float(builtin_float) => match builtin_float {
|
||||
// FIXME:
|
||||
hir_def::builtin_type::BuiltinFloat::F16 => Box::new([0u8; 2]) as Box<[u8]>,
|
||||
hir_def::builtin_type::BuiltinFloat::F32 => {
|
||||
Box::new(float_type_wrapper.to_f32().to_le_bytes())
|
||||
}
|
||||
hir_def::builtin_type::BuiltinFloat::F64 => {
|
||||
Box::new(float_type_wrapper.to_f64().to_le_bytes())
|
||||
}
|
||||
// FIXME:
|
||||
hir_def::builtin_type::BuiltinFloat::F128 => Box::new([0; 16]),
|
||||
},
|
||||
_ => unreachable!(),
|
||||
};
|
||||
rustc_type_ir::ConstKind::Value(ValueConst::new(
|
||||
ty,
|
||||
ConstBytes { memory, memory_map: MemoryMap::default() },
|
||||
))
|
||||
}
|
||||
Literal::Bool(b) if ty.is_bool() => rustc_type_ir::ConstKind::Value(ValueConst::new(
|
||||
ty,
|
||||
ConstBytes { memory: Box::new([*b as u8]), memory_map: MemoryMap::default() },
|
||||
)),
|
||||
LiteralConstRef::Char(c) => rustc_type_ir::ConstKind::Value(ValueConst::new(
|
||||
Literal::Char(c) if ty.is_char() => rustc_type_ir::ConstKind::Value(ValueConst::new(
|
||||
ty,
|
||||
ConstBytes {
|
||||
memory: (*c as u32).to_le_bytes().into(),
|
||||
memory_map: MemoryMap::default(),
|
||||
},
|
||||
)),
|
||||
LiteralConstRef::Unknown => rustc_type_ir::ConstKind::Error(ErrorGuaranteed),
|
||||
Literal::String(symbol) if ty.is_str() => rustc_type_ir::ConstKind::Value(ValueConst::new(
|
||||
ty,
|
||||
ConstBytes {
|
||||
memory: symbol.as_str().as_bytes().into(),
|
||||
memory_map: MemoryMap::default(),
|
||||
},
|
||||
)),
|
||||
Literal::ByteString(items) if ty.as_slice().is_some_and(|ty| ty.is_u8()) => {
|
||||
rustc_type_ir::ConstKind::Value(ValueConst::new(
|
||||
ty,
|
||||
ConstBytes { memory: items.clone(), memory_map: MemoryMap::default() },
|
||||
))
|
||||
}
|
||||
// FIXME
|
||||
Literal::CString(_items) => rustc_type_ir::ConstKind::Error(ErrorGuaranteed),
|
||||
_ => rustc_type_ir::ConstKind::Error(ErrorGuaranteed),
|
||||
};
|
||||
Const::new(interner, kind)
|
||||
}
|
||||
@@ -130,7 +205,15 @@ pub fn intern_const_ref<'a>(
|
||||
pub fn usize_const<'db>(db: &'db dyn HirDatabase, value: Option<u128>, krate: Crate) -> Const<'db> {
|
||||
intern_const_ref(
|
||||
db,
|
||||
&value.map_or(LiteralConstRef::Unknown, LiteralConstRef::UInt),
|
||||
&match value {
|
||||
Some(value) => Literal::Uint(value, Some(BuiltinUint::Usize)),
|
||||
None => {
|
||||
return Const::new(
|
||||
DbInterner::new_no_crate(db),
|
||||
rustc_type_ir::ConstKind::Error(ErrorGuaranteed),
|
||||
);
|
||||
}
|
||||
},
|
||||
Ty::new_uint(DbInterner::new_no_crate(db), rustc_type_ir::UintTy::Usize),
|
||||
krate,
|
||||
)
|
||||
|
||||
@@ -2209,6 +2209,7 @@ fn boxes() {
|
||||
check_number(
|
||||
r#"
|
||||
//- minicore: coerce_unsized, deref_mut, slice
|
||||
#![feature(lang_items)]
|
||||
use core::ops::{Deref, DerefMut};
|
||||
use core::{marker::Unsize, ops::CoerceUnsized};
|
||||
|
||||
@@ -2346,6 +2347,7 @@ fn c_string() {
|
||||
check_number(
|
||||
r#"
|
||||
//- minicore: index, slice
|
||||
#![feature(lang_items)]
|
||||
#[lang = "CStr"]
|
||||
pub struct CStr {
|
||||
inner: [u8]
|
||||
@@ -2360,6 +2362,7 @@ pub struct CStr {
|
||||
check_number(
|
||||
r#"
|
||||
//- minicore: index, slice
|
||||
#![feature(lang_items)]
|
||||
#[lang = "CStr"]
|
||||
pub struct CStr {
|
||||
inner: [u8]
|
||||
|
||||
@@ -10,7 +10,8 @@
|
||||
use base_db::{Crate, FxIndexMap};
|
||||
use either::Either;
|
||||
use hir_def::{
|
||||
FindPathConfig, GenericDefId, HasModule, LocalFieldId, Lookup, ModuleDefId, ModuleId, TraitId,
|
||||
FindPathConfig, GenericDefId, GenericParamId, HasModule, LocalFieldId, Lookup, ModuleDefId,
|
||||
ModuleId, TraitId,
|
||||
db::DefDatabase,
|
||||
expr_store::{ExpressionStore, path::Path},
|
||||
find_path::{self, PrefixKind},
|
||||
@@ -66,6 +67,7 @@
|
||||
|
||||
pub trait HirWrite: fmt::Write {
|
||||
fn start_location_link(&mut self, _location: ModuleDefId) {}
|
||||
fn start_location_link_generic(&mut self, _location: GenericParamId) {}
|
||||
fn end_location_link(&mut self) {}
|
||||
}
|
||||
|
||||
@@ -147,6 +149,10 @@ pub fn start_location_link(&mut self, location: ModuleDefId) {
|
||||
self.fmt.start_location_link(location);
|
||||
}
|
||||
|
||||
pub fn start_location_link_generic(&mut self, location: GenericParamId) {
|
||||
self.fmt.start_location_link_generic(location);
|
||||
}
|
||||
|
||||
pub fn end_location_link(&mut self) {
|
||||
self.fmt.end_location_link();
|
||||
}
|
||||
@@ -686,7 +692,9 @@ fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result {
|
||||
ConstKind::Param(param) => {
|
||||
let generics = generics(f.db, param.id.parent());
|
||||
let param_data = &generics[param.id.local_id()];
|
||||
f.start_location_link_generic(param.id.into());
|
||||
write!(f, "{}", param_data.name().unwrap().display(f.db, f.edition()))?;
|
||||
f.end_location_link();
|
||||
Ok(())
|
||||
}
|
||||
ConstKind::Value(const_bytes) => render_const_scalar(
|
||||
@@ -1489,6 +1497,7 @@ fn hir_fmt(&self, f @ &mut HirFormatter { db, .. }: &mut HirFormatter<'_, 'db>)
|
||||
match param_data {
|
||||
TypeOrConstParamData::TypeParamData(p) => match p.provenance {
|
||||
TypeParamProvenance::TypeParamList | TypeParamProvenance::TraitSelf => {
|
||||
f.start_location_link_generic(param.id.into());
|
||||
write!(
|
||||
f,
|
||||
"{}",
|
||||
@@ -1496,7 +1505,8 @@ fn hir_fmt(&self, f @ &mut HirFormatter { db, .. }: &mut HirFormatter<'_, 'db>)
|
||||
.clone()
|
||||
.unwrap_or_else(Name::missing)
|
||||
.display(f.db, f.edition())
|
||||
)?
|
||||
)?;
|
||||
f.end_location_link();
|
||||
}
|
||||
TypeParamProvenance::ArgumentImplTrait => {
|
||||
let bounds = GenericPredicates::query_all(f.db, param.id.parent())
|
||||
@@ -1519,7 +1529,9 @@ fn hir_fmt(&self, f @ &mut HirFormatter { db, .. }: &mut HirFormatter<'_, 'db>)
|
||||
}
|
||||
},
|
||||
TypeOrConstParamData::ConstParamData(p) => {
|
||||
f.start_location_link_generic(param.id.into());
|
||||
write!(f, "{}", p.name.display(f.db, f.edition()))?;
|
||||
f.end_location_link();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2031,7 +2043,9 @@ fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result {
|
||||
RegionKind::ReEarlyParam(param) => {
|
||||
let generics = generics(f.db, param.id.parent);
|
||||
let param_data = &generics[param.id.local_id];
|
||||
f.start_location_link_generic(param.id.into());
|
||||
write!(f, "{}", param_data.name.display(f.db, f.edition()))?;
|
||||
f.end_location_link();
|
||||
Ok(())
|
||||
}
|
||||
RegionKind::ReBound(BoundVarIndexKind::Bound(db), idx) => {
|
||||
|
||||
@@ -27,8 +27,8 @@
|
||||
resolver::{HasResolver, LifetimeNs, Resolver, TypeNs, ValueNs},
|
||||
signatures::{FunctionSignature, TraitFlags, TypeAliasFlags},
|
||||
type_ref::{
|
||||
ConstRef, LifetimeRefId, LiteralConstRef, PathId, TraitBoundModifier,
|
||||
TraitRef as HirTraitRef, TypeBound, TypeRef, TypeRefId,
|
||||
ConstRef, LifetimeRefId, PathId, TraitBoundModifier, TraitRef as HirTraitRef, TypeBound,
|
||||
TypeRef, TypeRefId,
|
||||
},
|
||||
};
|
||||
use hir_expand::name::Name;
|
||||
@@ -281,21 +281,9 @@ pub(crate) fn lower_const(&mut self, const_ref: ConstRef, const_type: Ty<'db>) -
|
||||
hir_def::hir::Expr::Path(path) => {
|
||||
self.path_to_const(path).unwrap_or_else(|| unknown_const(const_type))
|
||||
}
|
||||
hir_def::hir::Expr::Literal(literal) => intern_const_ref(
|
||||
self.db,
|
||||
&match *literal {
|
||||
hir_def::hir::Literal::Float(_, _)
|
||||
| hir_def::hir::Literal::String(_)
|
||||
| hir_def::hir::Literal::ByteString(_)
|
||||
| hir_def::hir::Literal::CString(_) => LiteralConstRef::Unknown,
|
||||
hir_def::hir::Literal::Char(c) => LiteralConstRef::Char(c),
|
||||
hir_def::hir::Literal::Bool(b) => LiteralConstRef::Bool(b),
|
||||
hir_def::hir::Literal::Int(val, _) => LiteralConstRef::Int(val),
|
||||
hir_def::hir::Literal::Uint(val, _) => LiteralConstRef::UInt(val),
|
||||
},
|
||||
const_type,
|
||||
self.resolver.krate(),
|
||||
),
|
||||
hir_def::hir::Expr::Literal(literal) => {
|
||||
intern_const_ref(self.db, literal, const_type, self.resolver.krate())
|
||||
}
|
||||
hir_def::hir::Expr::UnaryOp { expr: inner_expr, op: hir_def::hir::UnaryOp::Neg } => {
|
||||
if let hir_def::hir::Expr::Literal(literal) = &self.store[*inner_expr] {
|
||||
// Only handle negation for signed integers and floats
|
||||
@@ -304,7 +292,7 @@ pub(crate) fn lower_const(&mut self, const_ref: ConstRef, const_type: Ty<'db>) -
|
||||
if let Some(negated_literal) = literal.clone().negate() {
|
||||
intern_const_ref(
|
||||
self.db,
|
||||
&negated_literal.into(),
|
||||
&negated_literal,
|
||||
const_type,
|
||||
self.resolver.krate(),
|
||||
)
|
||||
@@ -1319,7 +1307,7 @@ fn type_for_struct_constructor(
|
||||
db: &dyn HirDatabase,
|
||||
def: StructId,
|
||||
) -> Option<StoredEarlyBinder<StoredTy>> {
|
||||
let struct_data = def.fields(db);
|
||||
let struct_data = db.struct_signature(def);
|
||||
match struct_data.shape {
|
||||
FieldsShape::Record => None,
|
||||
FieldsShape::Unit => Some(type_for_adt(db, def.into())),
|
||||
|
||||
@@ -609,12 +609,7 @@ fn collect(
|
||||
map: &mut FxHashMap<SimplifiedType, Vec<ImplId>>,
|
||||
) {
|
||||
for (_module_id, module_data) in def_map.modules() {
|
||||
for impl_id in module_data.scope.impls() {
|
||||
let data = db.impl_signature(impl_id);
|
||||
if data.target_trait.is_some() {
|
||||
continue;
|
||||
}
|
||||
|
||||
for impl_id in module_data.scope.inherent_impls() {
|
||||
let interner = DbInterner::new_no_crate(db);
|
||||
let self_ty = db.impl_self_ty(impl_id);
|
||||
let self_ty = self_ty.instantiate_identity();
|
||||
@@ -730,7 +725,11 @@ fn collect(
|
||||
map: &mut FxHashMap<TraitId, OneTraitImplsBuilder>,
|
||||
) {
|
||||
for (_module_id, module_data) in def_map.modules() {
|
||||
for impl_id in module_data.scope.impls() {
|
||||
for impl_id in module_data.scope.trait_impls() {
|
||||
let trait_ref = match db.impl_trait(impl_id) {
|
||||
Some(tr) => tr.instantiate_identity(),
|
||||
None => continue,
|
||||
};
|
||||
// Reservation impls should be ignored during trait resolution, so we never need
|
||||
// them during type analysis. See rust-lang/rust#64631 for details.
|
||||
//
|
||||
@@ -742,10 +741,6 @@ fn collect(
|
||||
{
|
||||
continue;
|
||||
}
|
||||
let trait_ref = match db.impl_trait(impl_id) {
|
||||
Some(tr) => tr.instantiate_identity(),
|
||||
None => continue,
|
||||
};
|
||||
let self_ty = trait_ref.self_ty();
|
||||
let interner = DbInterner::new_no_crate(db);
|
||||
let entry = map.entry(trait_ref.def_id.0).or_default();
|
||||
|
||||
@@ -878,9 +878,11 @@ pub fn set_tainted_by_errors(&self, e: ErrorGuaranteed) {
|
||||
self.tainted_by_errors.set(Some(e));
|
||||
}
|
||||
|
||||
#[instrument(level = "debug", skip(self), ret)]
|
||||
pub fn take_opaque_types(&self) -> Vec<(OpaqueTypeKey<'db>, OpaqueHiddenType<'db>)> {
|
||||
self.inner.borrow_mut().opaque_type_storage.take_opaque_types().collect()
|
||||
#[instrument(level = "debug", skip(self))]
|
||||
pub fn take_opaque_types(
|
||||
&self,
|
||||
) -> impl IntoIterator<Item = (OpaqueTypeKey<'db>, OpaqueHiddenType<'db>)> + use<'db> {
|
||||
self.inner.borrow_mut().opaque_type_storage.take_opaque_types()
|
||||
}
|
||||
|
||||
#[instrument(level = "debug", skip(self), ret)]
|
||||
|
||||
@@ -61,7 +61,7 @@ pub(crate) fn is_empty(&self) -> bool {
|
||||
|
||||
pub(crate) fn take_opaque_types(
|
||||
&mut self,
|
||||
) -> impl Iterator<Item = (OpaqueTypeKey<'db>, OpaqueHiddenType<'db>)> {
|
||||
) -> impl IntoIterator<Item = (OpaqueTypeKey<'db>, OpaqueHiddenType<'db>)> + use<'db> {
|
||||
let OpaqueTypeStorage { opaque_types, duplicate_entries } = self;
|
||||
std::mem::take(opaque_types).into_iter().chain(std::mem::take(duplicate_entries))
|
||||
}
|
||||
|
||||
@@ -383,6 +383,11 @@ pub fn is_bool(self) -> bool {
|
||||
matches!(self.kind(), TyKind::Bool)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn is_char(self) -> bool {
|
||||
matches!(self.kind(), TyKind::Char)
|
||||
}
|
||||
|
||||
/// A scalar type is one that denotes an atomic datum, with no sub-components.
|
||||
/// (A RawPtr is scalar because it represents a non-managed pointer, so its
|
||||
/// contents are abstract to rustc.)
|
||||
@@ -422,6 +427,11 @@ pub fn is_unit(self) -> bool {
|
||||
matches!(self.kind(), TyKind::Tuple(tys) if tys.is_empty())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn is_u8(self) -> bool {
|
||||
matches!(self.kind(), TyKind::Uint(UintTy::U8))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn is_raw_ptr(self) -> bool {
|
||||
matches!(self.kind(), TyKind::RawPtr(..))
|
||||
@@ -456,6 +466,14 @@ pub fn as_adt(self) -> Option<(AdtId, GenericArgs<'db>)> {
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn as_slice(self) -> Option<Ty<'db>> {
|
||||
match self.kind() {
|
||||
TyKind::Slice(ty) => Some(ty),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn ty_vid(self) -> Option<TyVid> {
|
||||
match self.kind() {
|
||||
|
||||
@@ -132,14 +132,13 @@ fn baz() -> i32 {
|
||||
"trait_environment_query",
|
||||
"lang_items",
|
||||
"crate_lang_items",
|
||||
"AttrFlags::query_",
|
||||
"AttrFlags::query_",
|
||||
"GenericPredicates::query_with_diagnostics_",
|
||||
"ImplTraits::return_type_impl_traits_",
|
||||
"expr_scopes_shim",
|
||||
"InferenceResult::for_body_",
|
||||
"function_signature_shim",
|
||||
"function_signature_with_source_map_shim",
|
||||
"AttrFlags::query_",
|
||||
"body_shim",
|
||||
"body_with_source_map_shim",
|
||||
"trait_environment_query",
|
||||
@@ -149,6 +148,7 @@ fn baz() -> i32 {
|
||||
"InferenceResult::for_body_",
|
||||
"function_signature_shim",
|
||||
"function_signature_with_source_map_shim",
|
||||
"AttrFlags::query_",
|
||||
"body_shim",
|
||||
"body_with_source_map_shim",
|
||||
"trait_environment_query",
|
||||
@@ -197,13 +197,13 @@ fn baz() -> i32 {
|
||||
"body_with_source_map_shim",
|
||||
"body_shim",
|
||||
"AttrFlags::query_",
|
||||
"AttrFlags::query_",
|
||||
"function_signature_with_source_map_shim",
|
||||
"function_signature_shim",
|
||||
"body_with_source_map_shim",
|
||||
"body_shim",
|
||||
"InferenceResult::for_body_",
|
||||
"expr_scopes_shim",
|
||||
"AttrFlags::query_",
|
||||
"function_signature_with_source_map_shim",
|
||||
"function_signature_shim",
|
||||
"body_with_source_map_shim",
|
||||
@@ -245,8 +245,6 @@ fn bar() -> f32 {
|
||||
"TraitImpls::for_crate_",
|
||||
"lang_items",
|
||||
"crate_lang_items",
|
||||
"AttrFlags::query_",
|
||||
"AttrFlags::query_",
|
||||
]
|
||||
"#]],
|
||||
);
|
||||
@@ -284,9 +282,6 @@ pub struct NewStruct {
|
||||
"crate_local_def_map",
|
||||
"TraitImpls::for_crate_",
|
||||
"crate_lang_items",
|
||||
"AttrFlags::query_",
|
||||
"AttrFlags::query_",
|
||||
"AttrFlags::query_",
|
||||
]
|
||||
"#]],
|
||||
);
|
||||
@@ -324,8 +319,6 @@ fn bar() -> f32 {
|
||||
"TraitImpls::for_crate_",
|
||||
"lang_items",
|
||||
"crate_lang_items",
|
||||
"AttrFlags::query_",
|
||||
"AttrFlags::query_",
|
||||
]
|
||||
"#]],
|
||||
);
|
||||
@@ -364,12 +357,6 @@ pub enum SomeEnum {
|
||||
"crate_local_def_map",
|
||||
"TraitImpls::for_crate_",
|
||||
"crate_lang_items",
|
||||
"AttrFlags::query_",
|
||||
"AttrFlags::query_",
|
||||
"AttrFlags::query_",
|
||||
"EnumVariants::of_",
|
||||
"AttrFlags::query_",
|
||||
"AttrFlags::query_",
|
||||
]
|
||||
"#]],
|
||||
);
|
||||
@@ -407,8 +394,6 @@ fn bar() -> f32 {
|
||||
"TraitImpls::for_crate_",
|
||||
"lang_items",
|
||||
"crate_lang_items",
|
||||
"AttrFlags::query_",
|
||||
"AttrFlags::query_",
|
||||
]
|
||||
"#]],
|
||||
);
|
||||
@@ -444,8 +429,6 @@ fn bar() -> f32 {
|
||||
"crate_local_def_map",
|
||||
"TraitImpls::for_crate_",
|
||||
"crate_lang_items",
|
||||
"AttrFlags::query_",
|
||||
"AttrFlags::query_",
|
||||
]
|
||||
"#]],
|
||||
);
|
||||
@@ -487,9 +470,6 @@ pub struct SomeStruct {
|
||||
"TraitImpls::for_crate_",
|
||||
"lang_items",
|
||||
"crate_lang_items",
|
||||
"AttrFlags::query_",
|
||||
"AttrFlags::query_",
|
||||
"AttrFlags::query_",
|
||||
]
|
||||
"#]],
|
||||
);
|
||||
@@ -533,18 +513,6 @@ pub fn new(value: i32) -> Self {
|
||||
"crate_local_def_map",
|
||||
"TraitImpls::for_crate_",
|
||||
"crate_lang_items",
|
||||
"AttrFlags::query_",
|
||||
"ImplItems::of_",
|
||||
"AttrFlags::query_",
|
||||
"AttrFlags::query_",
|
||||
"AttrFlags::query_",
|
||||
"AttrFlags::query_",
|
||||
"impl_trait_with_diagnostics_query",
|
||||
"impl_signature_shim",
|
||||
"impl_signature_with_source_map_shim",
|
||||
"impl_self_ty_with_diagnostics_query",
|
||||
"struct_signature_shim",
|
||||
"struct_signature_with_source_map_shim",
|
||||
]
|
||||
"#]],
|
||||
);
|
||||
@@ -616,8 +584,6 @@ fn main() {
|
||||
"trait_environment_query",
|
||||
"lang_items",
|
||||
"crate_lang_items",
|
||||
"AttrFlags::query_",
|
||||
"AttrFlags::query_",
|
||||
"GenericPredicates::query_with_diagnostics_",
|
||||
"GenericPredicates::query_with_diagnostics_",
|
||||
"ImplTraits::return_type_impl_traits_",
|
||||
@@ -630,18 +596,18 @@ fn main() {
|
||||
"expr_scopes_shim",
|
||||
"struct_signature_shim",
|
||||
"struct_signature_with_source_map_shim",
|
||||
"AttrFlags::query_",
|
||||
"GenericPredicates::query_with_diagnostics_",
|
||||
"value_ty_query",
|
||||
"VariantFields::firewall_",
|
||||
"VariantFields::query_",
|
||||
"InherentImpls::for_crate_",
|
||||
"impl_signature_shim",
|
||||
"impl_signature_with_source_map_shim",
|
||||
"callable_item_signature_query",
|
||||
"TraitImpls::for_crate_and_deps_",
|
||||
"TraitImpls::for_crate_",
|
||||
"impl_trait_with_diagnostics_query",
|
||||
"impl_signature_shim",
|
||||
"impl_signature_with_source_map_shim",
|
||||
"impl_self_ty_with_diagnostics_query",
|
||||
"AttrFlags::query_",
|
||||
"GenericPredicates::query_with_diagnostics_",
|
||||
]
|
||||
"#]],
|
||||
@@ -710,9 +676,6 @@ fn main() {
|
||||
"body_with_source_map_shim",
|
||||
"body_shim",
|
||||
"crate_lang_items",
|
||||
"AttrFlags::query_",
|
||||
"AttrFlags::query_",
|
||||
"AttrFlags::query_",
|
||||
"GenericPredicates::query_with_diagnostics_",
|
||||
"GenericPredicates::query_with_diagnostics_",
|
||||
"ImplTraits::return_type_impl_traits_",
|
||||
@@ -722,15 +685,16 @@ fn main() {
|
||||
"ImplTraits::return_type_impl_traits_",
|
||||
"expr_scopes_shim",
|
||||
"struct_signature_with_source_map_shim",
|
||||
"AttrFlags::query_",
|
||||
"GenericPredicates::query_with_diagnostics_",
|
||||
"VariantFields::query_",
|
||||
"InherentImpls::for_crate_",
|
||||
"impl_signature_with_source_map_shim",
|
||||
"impl_signature_shim",
|
||||
"callable_item_signature_query",
|
||||
"TraitImpls::for_crate_",
|
||||
"impl_signature_with_source_map_shim",
|
||||
"impl_signature_shim",
|
||||
"impl_trait_with_diagnostics_query",
|
||||
"impl_self_ty_with_diagnostics_query",
|
||||
"AttrFlags::query_",
|
||||
"GenericPredicates::query_with_diagnostics_",
|
||||
]
|
||||
"#]],
|
||||
|
||||
@@ -794,6 +794,8 @@ fn foo(params: &[i32]) {
|
||||
fn box_pattern() {
|
||||
check_infer(
|
||||
r#"
|
||||
#![feature(lang_items)]
|
||||
|
||||
pub struct Global;
|
||||
#[lang = "owned_box"]
|
||||
pub struct Box<T, A = Global>(T);
|
||||
@@ -805,13 +807,13 @@ fn foo(params: Box<i32>) {
|
||||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
83..89 'params': Box<i32, Global>
|
||||
101..155 '{ ... } }': ()
|
||||
107..153 'match ... }': ()
|
||||
113..119 'params': Box<i32, Global>
|
||||
130..141 'box integer': Box<i32, Global>
|
||||
134..141 'integer': i32
|
||||
145..147 '{}': ()
|
||||
108..114 'params': Box<i32, Global>
|
||||
126..180 '{ ... } }': ()
|
||||
132..178 'match ... }': ()
|
||||
138..144 'params': Box<i32, Global>
|
||||
155..166 'box integer': Box<i32, Global>
|
||||
159..166 'integer': i32
|
||||
170..172 '{}': ()
|
||||
"#]],
|
||||
);
|
||||
check_infer(
|
||||
@@ -831,7 +833,6 @@ fn foo(params: Box<i32>) {
|
||||
76..122 'match ... }': ()
|
||||
82..88 'params': Box<i32>
|
||||
99..110 'box integer': Box<i32>
|
||||
103..110 'integer': i32
|
||||
114..116 '{}': ()
|
||||
"#]],
|
||||
);
|
||||
@@ -1142,6 +1143,7 @@ fn my_fn(#[cfg(feature = "feature")] u8: u8, u32: u32) {}
|
||||
fn var_args() {
|
||||
check_types(
|
||||
r#"
|
||||
#![feature(lang_items)]
|
||||
#[lang = "va_list"]
|
||||
pub struct VaListImpl<'f>;
|
||||
fn my_fn(foo: ...) {}
|
||||
@@ -1156,6 +1158,7 @@ fn my_fn2(bar: u32, foo: ...) {}
|
||||
fn var_args_cond() {
|
||||
check_types(
|
||||
r#"
|
||||
#![feature(lang_items)]
|
||||
#[lang = "va_list"]
|
||||
pub struct VaListImpl<'f>;
|
||||
fn my_fn(bar: u32, #[cfg(FALSE)] foo: ..., #[cfg(not(FALSE))] foo: u32) {
|
||||
|
||||
@@ -2374,6 +2374,7 @@ fn rust_destruct_option_clone() {
|
||||
check_types(
|
||||
r#"
|
||||
//- minicore: option, drop
|
||||
#![feature(lang_items)]
|
||||
fn test(o: &Option<i32>) {
|
||||
o.my_clone();
|
||||
//^^^^^^^^^^^^ Option<i32>
|
||||
|
||||
@@ -234,6 +234,7 @@ fn main() {
|
||||
// toolchains <= 1.88.0, before sized-hierarchy.
|
||||
check_no_mismatches(
|
||||
r#"
|
||||
#![feature(lang_items)]
|
||||
#[lang = "sized"]
|
||||
pub trait Sized {}
|
||||
|
||||
|
||||
@@ -2702,6 +2702,8 @@ fn box_into_vec() {
|
||||
check_infer(
|
||||
r#"
|
||||
//- /core.rs crate:core
|
||||
#![feature(lang_items)]
|
||||
|
||||
#[lang = "sized"]
|
||||
pub trait Sized {}
|
||||
|
||||
@@ -2745,22 +2747,22 @@ trait B{}
|
||||
impl B for Astruct {}
|
||||
"#,
|
||||
expect![[r#"
|
||||
614..618 'self': Box<[T], A>
|
||||
647..679 '{ ... }': Vec<T, A>
|
||||
693..863 '{ ...])); }': ()
|
||||
703..706 'vec': Vec<i32, Global>
|
||||
709..724 '<[_]>::into_vec': fn into_vec<i32, Global>(Box<[i32], Global>) -> Vec<i32, Global>
|
||||
709..755 '<[_]>:...i32]))': Vec<i32, Global>
|
||||
725..754 '#[rust...1i32])': Box<[i32; 1], Global>
|
||||
747..753 '[1i32]': [i32; 1]
|
||||
748..752 '1i32': i32
|
||||
765..766 'v': Vec<Box<dyn B + 'static, Global>, Global>
|
||||
786..803 '<[_]> ...to_vec': fn into_vec<Box<dyn B + '?, Global>, Global>(Box<[Box<dyn B + '?, Global>], Global>) -> Vec<Box<dyn B + '?, Global>, Global>
|
||||
786..860 '<[_]> ...ct)]))': Vec<Box<dyn B + '?, Global>, Global>
|
||||
804..859 '#[rust...uct)])': Box<[Box<dyn B + '?, Global>; 1], Global>
|
||||
826..858 '[#[rus...ruct)]': [Box<dyn B + '?, Global>; 1]
|
||||
827..857 '#[rust...truct)': Box<Astruct, Global>
|
||||
849..856 'Astruct': Astruct
|
||||
639..643 'self': Box<[T], A>
|
||||
672..704 '{ ... }': Vec<T, A>
|
||||
718..888 '{ ...])); }': ()
|
||||
728..731 'vec': Vec<i32, Global>
|
||||
734..749 '<[_]>::into_vec': fn into_vec<i32, Global>(Box<[i32], Global>) -> Vec<i32, Global>
|
||||
734..780 '<[_]>:...i32]))': Vec<i32, Global>
|
||||
750..779 '#[rust...1i32])': Box<[i32; 1], Global>
|
||||
772..778 '[1i32]': [i32; 1]
|
||||
773..777 '1i32': i32
|
||||
790..791 'v': Vec<Box<dyn B + 'static, Global>, Global>
|
||||
811..828 '<[_]> ...to_vec': fn into_vec<Box<dyn B + '?, Global>, Global>(Box<[Box<dyn B + '?, Global>], Global>) -> Vec<Box<dyn B + '?, Global>, Global>
|
||||
811..885 '<[_]> ...ct)]))': Vec<Box<dyn B + '?, Global>, Global>
|
||||
829..884 '#[rust...uct)])': Box<[Box<dyn B + '?, Global>; 1], Global>
|
||||
851..883 '[#[rus...ruct)]': [Box<dyn B + '?, Global>; 1]
|
||||
852..882 '#[rust...truct)': Box<Astruct, Global>
|
||||
874..881 'Astruct': Astruct
|
||||
"#]],
|
||||
)
|
||||
}
|
||||
@@ -3647,6 +3649,8 @@ fn main() {
|
||||
fn cstring_literals() {
|
||||
check_types(
|
||||
r#"
|
||||
#![feature(lang_items)]
|
||||
|
||||
#[lang = "CStr"]
|
||||
pub struct CStr;
|
||||
|
||||
|
||||
@@ -41,7 +41,6 @@ pub(crate) fn variances_of(db: &dyn HirDatabase, def: GenericDefId) -> Variances
|
||||
)]
|
||||
fn variances_of_query(db: &dyn HirDatabase, def: GenericDefId) -> StoredVariancesOf {
|
||||
tracing::debug!("variances_of(def={:?})", def);
|
||||
let interner = DbInterner::new_no_crate(db);
|
||||
match def {
|
||||
GenericDefId::FunctionId(_) => (),
|
||||
GenericDefId::AdtId(adt) => {
|
||||
@@ -55,15 +54,17 @@ fn variances_of_query(db: &dyn HirDatabase, def: GenericDefId) -> StoredVariance
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => return VariancesOf::empty(interner).store(),
|
||||
_ => return VariancesOf::empty(DbInterner::new_no_crate(db)).store(),
|
||||
}
|
||||
|
||||
let generics = generics(db, def);
|
||||
let count = generics.len();
|
||||
if count == 0 {
|
||||
return VariancesOf::empty(interner).store();
|
||||
return VariancesOf::empty(DbInterner::new_no_crate(db)).store();
|
||||
}
|
||||
let variances = Context { generics, variances: vec![Variance::Bivariant; count], db }.solve();
|
||||
let variances =
|
||||
Context { generics, variances: vec![Variance::Bivariant; count].into_boxed_slice(), db }
|
||||
.solve();
|
||||
|
||||
VariancesOf::new_from_slice(&variances).store()
|
||||
}
|
||||
@@ -113,11 +114,11 @@ pub(crate) fn variances_of_cycle_initial(
|
||||
struct Context<'db> {
|
||||
db: &'db dyn HirDatabase,
|
||||
generics: Generics,
|
||||
variances: Vec<Variance>,
|
||||
variances: Box<[Variance]>,
|
||||
}
|
||||
|
||||
impl<'db> Context<'db> {
|
||||
fn solve(mut self) -> Vec<Variance> {
|
||||
fn solve(mut self) -> Box<[Variance]> {
|
||||
tracing::debug!("solve(generics={:?})", self.generics);
|
||||
match self.generics.def() {
|
||||
GenericDefId::AdtId(adt) => {
|
||||
|
||||
@@ -330,7 +330,7 @@ fn source(self, db: &dyn HirDatabase) -> Option<InFile<Self::Ast>> {
|
||||
let (_body, source_map) = db.body_with_source_map(self.parent);
|
||||
let src = source_map.label_syntax(self.label_id);
|
||||
let root = src.file_syntax(db);
|
||||
Some(src.map(|ast| ast.to_node(&root)))
|
||||
src.map(|ast| ast.to_node(&root).left()).transpose()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -50,9 +50,9 @@
|
||||
use hir_def::{
|
||||
AdtId, AssocItemId, AssocItemLoc, BuiltinDeriveImplId, CallableDefId, ConstId, ConstParamId,
|
||||
DefWithBodyId, EnumId, EnumVariantId, ExternBlockId, ExternCrateId, FunctionId, GenericDefId,
|
||||
GenericParamId, HasModule, ImplId, ItemContainerId, LifetimeParamId, LocalFieldId, Lookup,
|
||||
MacroExpander, MacroId, StaticId, StructId, SyntheticSyntax, TupleId, TypeAliasId,
|
||||
TypeOrConstParamId, TypeParamId, UnionId,
|
||||
HasModule, ImplId, ItemContainerId, LifetimeParamId, LocalFieldId, Lookup, MacroExpander,
|
||||
MacroId, StaticId, StructId, SyntheticSyntax, TupleId, TypeAliasId, TypeOrConstParamId,
|
||||
TypeParamId, UnionId,
|
||||
attrs::AttrFlags,
|
||||
builtin_derive::BuiltinDeriveImplMethod,
|
||||
expr_store::{ExpressionStoreDiagnostics, ExpressionStoreSourceMap},
|
||||
@@ -150,7 +150,7 @@
|
||||
visibility::Visibility,
|
||||
// FIXME: This is here since some queries take it as input that are used
|
||||
// outside of hir.
|
||||
{ModuleDefId, TraitId},
|
||||
{GenericParamId, ModuleDefId, TraitId},
|
||||
},
|
||||
hir_expand::{
|
||||
EditionedFileId, ExpandResult, HirFileId, MacroCallId, MacroKind,
|
||||
@@ -803,22 +803,21 @@ pub fn diagnostics<'db>(
|
||||
emit_def_diagnostic(db, acc, diag, edition, loc.container.krate(db));
|
||||
}
|
||||
|
||||
if impl_signature.target_trait.is_none()
|
||||
&& !is_inherent_impl_coherent(db, def_map, impl_id)
|
||||
{
|
||||
let trait_impl = impl_signature.target_trait.is_some();
|
||||
if !trait_impl && !is_inherent_impl_coherent(db, def_map, impl_id) {
|
||||
acc.push(IncoherentImpl { impl_: ast_id_map.get(loc.id.value), file_id }.into())
|
||||
}
|
||||
|
||||
if !impl_def.check_orphan_rules(db) {
|
||||
if trait_impl && !impl_def.check_orphan_rules(db) {
|
||||
acc.push(TraitImplOrphan { impl_: ast_id_map.get(loc.id.value), file_id }.into())
|
||||
}
|
||||
|
||||
let trait_ = impl_def.trait_(db);
|
||||
let trait_ = trait_impl.then(|| impl_def.trait_(db)).flatten();
|
||||
let mut trait_is_unsafe = trait_.is_some_and(|t| t.is_unsafe(db));
|
||||
let impl_is_negative = impl_def.is_negative(db);
|
||||
let impl_is_unsafe = impl_def.is_unsafe(db);
|
||||
|
||||
let trait_is_unresolved = trait_.is_none() && impl_signature.target_trait.is_some();
|
||||
let trait_is_unresolved = trait_.is_none() && trait_impl;
|
||||
if trait_is_unresolved {
|
||||
// Ignore trait safety errors when the trait is unresolved, as otherwise we'll treat it as safe,
|
||||
// which may not be correct.
|
||||
@@ -921,6 +920,48 @@ pub fn diagnostics<'db>(
|
||||
}
|
||||
}
|
||||
|
||||
// HACK: When specialization is enabled in the current crate, and there exists
|
||||
// *any* blanket impl that provides a default implementation for the missing item,
|
||||
// suppress the missing associated item diagnostic.
|
||||
// This can lead to false negatives when the impl in question does not actually
|
||||
// specialize that blanket impl, but determining the exact specialization
|
||||
// relationship here would be significantly more expensive.
|
||||
if !missing.is_empty() {
|
||||
let krate = self.krate(db).id;
|
||||
let def_map = crate_def_map(db, krate);
|
||||
if def_map.is_unstable_feature_enabled(&sym::specialization)
|
||||
|| def_map.is_unstable_feature_enabled(&sym::min_specialization)
|
||||
{
|
||||
missing.retain(|(assoc_name, assoc_item)| {
|
||||
let AssocItem::Function(_) = assoc_item else {
|
||||
return true;
|
||||
};
|
||||
|
||||
for &impl_ in TraitImpls::for_crate(db, krate).blanket_impls(trait_.id)
|
||||
{
|
||||
if impl_ == impl_id {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (name, item) in &impl_.impl_items(db).items {
|
||||
let AssocItemId::FunctionId(fn_) = item else {
|
||||
continue;
|
||||
};
|
||||
if name != assoc_name {
|
||||
continue;
|
||||
}
|
||||
|
||||
if db.function_signature(*fn_).is_default() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
true
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if !missing.is_empty() {
|
||||
acc.push(
|
||||
TraitImplMissingAssocItems {
|
||||
|
||||
@@ -1,6 +1,11 @@
|
||||
use itertools::Itertools;
|
||||
use syntax::{
|
||||
SyntaxKind::WHITESPACE,
|
||||
ast::{AstNode, BlockExpr, ElseBranch, Expr, IfExpr, MatchArm, Pat, edit::AstNodeEdit, make},
|
||||
ast::{
|
||||
AstNode, BlockExpr, ElseBranch, Expr, IfExpr, MatchArm, Pat, edit::AstNodeEdit, make,
|
||||
syntax_factory::SyntaxFactory,
|
||||
},
|
||||
syntax_editor::Element,
|
||||
};
|
||||
|
||||
use crate::{AssistContext, AssistId, Assists};
|
||||
@@ -131,8 +136,10 @@ pub(crate) fn move_arm_cond_to_match_guard(
|
||||
AssistId::refactor_rewrite("move_arm_cond_to_match_guard"),
|
||||
"Move condition to match guard",
|
||||
replace_node.text_range(),
|
||||
|edit| {
|
||||
edit.delete(match_arm.syntax().text_range());
|
||||
|builder| {
|
||||
let make = SyntaxFactory::without_mappings();
|
||||
let mut replace_arms = vec![];
|
||||
|
||||
// Dedent if if_expr is in a BlockExpr
|
||||
let dedent = if needs_dedent {
|
||||
cov_mark::hit!(move_guard_ifelse_in_block);
|
||||
@@ -141,47 +148,30 @@ pub(crate) fn move_arm_cond_to_match_guard(
|
||||
cov_mark::hit!(move_guard_ifelse_else_block);
|
||||
0
|
||||
};
|
||||
let then_arm_end = match_arm.syntax().text_range().end();
|
||||
let indent_level = match_arm.indent_level();
|
||||
let spaces = indent_level;
|
||||
|
||||
let mut first = true;
|
||||
for (cond, block) in conds_blocks {
|
||||
if !first {
|
||||
edit.insert(then_arm_end, format!("\n{spaces}"));
|
||||
} else {
|
||||
first = false;
|
||||
}
|
||||
let guard = format!("{match_pat} if {cond} => ");
|
||||
edit.insert(then_arm_end, guard);
|
||||
let only_expr = block.statements().next().is_none();
|
||||
match &block.tail_expr() {
|
||||
Some(then_expr) if only_expr => {
|
||||
edit.insert(then_arm_end, then_expr.syntax().text());
|
||||
edit.insert(then_arm_end, ",");
|
||||
}
|
||||
_ => {
|
||||
let to_insert = block.dedent(dedent.into()).syntax().text();
|
||||
edit.insert(then_arm_end, to_insert)
|
||||
}
|
||||
}
|
||||
let expr = match block.tail_expr() {
|
||||
Some(then_expr) if only_expr => then_expr,
|
||||
_ => block.dedent(dedent.into()).into(),
|
||||
};
|
||||
let guard = make.match_guard(cond);
|
||||
let new_arm = make.match_arm(match_pat.clone(), Some(guard), expr);
|
||||
replace_arms.push(new_arm);
|
||||
}
|
||||
if let Some(e) = tail {
|
||||
if let Some(block) = tail {
|
||||
cov_mark::hit!(move_guard_ifelse_else_tail);
|
||||
let guard = format!("\n{spaces}{match_pat} => ");
|
||||
edit.insert(then_arm_end, guard);
|
||||
let only_expr = e.statements().next().is_none();
|
||||
match &e.tail_expr() {
|
||||
let only_expr = block.statements().next().is_none();
|
||||
let expr = match block.tail_expr() {
|
||||
Some(expr) if only_expr => {
|
||||
cov_mark::hit!(move_guard_ifelse_expr_only);
|
||||
edit.insert(then_arm_end, expr.syntax().text());
|
||||
edit.insert(then_arm_end, ",");
|
||||
expr
|
||||
}
|
||||
_ => {
|
||||
let to_insert = e.dedent(dedent.into()).syntax().text();
|
||||
edit.insert(then_arm_end, to_insert)
|
||||
}
|
||||
}
|
||||
_ => block.dedent(dedent.into()).into(),
|
||||
};
|
||||
let new_arm = make.match_arm(match_pat, None, expr);
|
||||
replace_arms.push(new_arm);
|
||||
} else {
|
||||
// There's no else branch. Add a pattern without guard, unless the following match
|
||||
// arm is `_ => ...`
|
||||
@@ -193,9 +183,21 @@ pub(crate) fn move_arm_cond_to_match_guard(
|
||||
{
|
||||
cov_mark::hit!(move_guard_ifelse_has_wildcard);
|
||||
}
|
||||
_ => edit.insert(then_arm_end, format!("\n{spaces}{match_pat} => {{}}")),
|
||||
_ => {
|
||||
let block_expr = make.expr_empty_block().into();
|
||||
replace_arms.push(make.match_arm(match_pat, None, block_expr));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let mut edit = builder.make_editor(match_arm.syntax());
|
||||
|
||||
let newline = make.whitespace(&format!("\n{indent_level}"));
|
||||
let replace_arms = replace_arms.iter().map(|it| it.syntax().syntax_element());
|
||||
let replace_arms = Itertools::intersperse(replace_arms, newline.syntax_element());
|
||||
edit.replace_with_many(match_arm.syntax(), replace_arms.collect());
|
||||
|
||||
builder.add_file_edits(ctx.vfs_file_id(), edit);
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
@@ -781,8 +781,8 @@ fn main() {
|
||||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
fn weird_function() (use dep::test_mod::TestTrait) fn() DEPRECATED
|
||||
ct SPECIAL_CONST (use dep::test_mod::TestTrait) u8 DEPRECATED
|
||||
fn weird_function() (use dep::test_mod::TestTrait) fn() DEPRECATED
|
||||
me random_method(…) (use dep::test_mod::TestTrait) fn(&self) DEPRECATED
|
||||
"#]],
|
||||
);
|
||||
|
||||
@@ -44,7 +44,7 @@
|
||||
/// `vec.as_slice()` -> `slice`
|
||||
/// `args.into_config()` -> `config`
|
||||
/// `bytes.to_vec()` -> `vec`
|
||||
const USELESS_METHOD_PREFIXES: &[&str] = &["into_", "as_", "to_"];
|
||||
const USELESS_METHOD_PREFIXES: &[&str] = &["try_into_", "into_", "as_", "to_"];
|
||||
|
||||
/// Useless methods that are stripped from expression
|
||||
///
|
||||
|
||||
+1
@@ -64,6 +64,7 @@ unsafe impl Unsafe for () {}
|
||||
fn drop_may_dangle() {
|
||||
check_diagnostics(
|
||||
r#"
|
||||
#![feature(lang_items)]
|
||||
#[lang = "drop"]
|
||||
trait Drop {}
|
||||
struct S<T>;
|
||||
|
||||
+18
@@ -156,4 +156,22 @@ impl Trait for dyn OtherTrait {}
|
||||
"#,
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn no_false_positive_on_specialization() {
|
||||
check_diagnostics(
|
||||
r#"
|
||||
#![feature(specialization)]
|
||||
|
||||
pub trait Foo {
|
||||
fn foo();
|
||||
}
|
||||
|
||||
impl<T> Foo for T {
|
||||
default fn foo() {}
|
||||
}
|
||||
impl Foo for bool {}
|
||||
"#,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4089,6 +4089,7 @@ fn foo() {
|
||||
let fo$0o = async { S };
|
||||
}
|
||||
//- /core.rs crate:core
|
||||
#![feature(lang_items)]
|
||||
pub mod future {
|
||||
#[lang = "future_trait"]
|
||||
pub trait Future {}
|
||||
|
||||
@@ -5,8 +5,8 @@
|
||||
|
||||
use either::Either;
|
||||
use hir::{
|
||||
ClosureStyle, DisplayTarget, EditionedFileId, HasVisibility, HirDisplay, HirDisplayError,
|
||||
HirWrite, InRealFile, ModuleDef, ModuleDefId, Semantics, sym,
|
||||
ClosureStyle, DisplayTarget, EditionedFileId, GenericParam, GenericParamId, HasVisibility,
|
||||
HirDisplay, HirDisplayError, HirWrite, InRealFile, ModuleDef, ModuleDefId, Semantics, sym,
|
||||
};
|
||||
use ide_db::{
|
||||
FileRange, MiniCore, RootDatabase, famous_defs::FamousDefs, text_edit::TextEditBuilder,
|
||||
@@ -709,6 +709,21 @@ fn start_location_link(&mut self, def: ModuleDefId) {
|
||||
});
|
||||
}
|
||||
|
||||
fn start_location_link_generic(&mut self, def: GenericParamId) {
|
||||
never!(self.location.is_some(), "location link is already started");
|
||||
self.make_new_part();
|
||||
|
||||
self.location = Some(if self.resolve {
|
||||
LazyProperty::Lazy
|
||||
} else {
|
||||
LazyProperty::Computed({
|
||||
let Some(location) = GenericParam::from(def).try_to_nav(self.sema) else { return };
|
||||
let location = location.call_site();
|
||||
FileRange { file_id: location.file_id, range: location.focus_or_full_range() }
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
fn end_location_link(&mut self) {
|
||||
self.make_new_part();
|
||||
}
|
||||
|
||||
@@ -183,7 +183,8 @@ mod tests {
|
||||
use crate::{ClosureReturnTypeHints, fixture, inlay_hints::InlayHintsConfig};
|
||||
|
||||
use crate::inlay_hints::tests::{
|
||||
DISABLED_CONFIG, TEST_CONFIG, check, check_edit, check_no_edit, check_with_config,
|
||||
DISABLED_CONFIG, TEST_CONFIG, check, check_edit, check_expect, check_no_edit,
|
||||
check_with_config,
|
||||
};
|
||||
|
||||
#[track_caller]
|
||||
@@ -1255,4 +1256,130 @@ fn f(&self) {
|
||||
"#,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn type_param_inlay_hint_has_location_link() {
|
||||
check_expect(
|
||||
InlayHintsConfig { type_hints: true, ..DISABLED_CONFIG },
|
||||
r#"
|
||||
fn identity<T>(t: T) -> T {
|
||||
let x = t;
|
||||
x
|
||||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
[
|
||||
(
|
||||
36..37,
|
||||
[
|
||||
InlayHintLabelPart {
|
||||
text: "T",
|
||||
linked_location: Some(
|
||||
Computed(
|
||||
FileRangeWrapper {
|
||||
file_id: FileId(
|
||||
0,
|
||||
),
|
||||
range: 12..13,
|
||||
},
|
||||
),
|
||||
),
|
||||
tooltip: "",
|
||||
},
|
||||
],
|
||||
),
|
||||
]
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn const_param_inlay_hint_has_location_link() {
|
||||
check_expect(
|
||||
InlayHintsConfig { type_hints: true, ..DISABLED_CONFIG },
|
||||
r#"
|
||||
fn f<const N: usize>() {
|
||||
let x = [0; N];
|
||||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
[
|
||||
(
|
||||
33..34,
|
||||
[
|
||||
"[i32; ",
|
||||
InlayHintLabelPart {
|
||||
text: "N",
|
||||
linked_location: Some(
|
||||
Computed(
|
||||
FileRangeWrapper {
|
||||
file_id: FileId(
|
||||
0,
|
||||
),
|
||||
range: 11..12,
|
||||
},
|
||||
),
|
||||
),
|
||||
tooltip: "",
|
||||
},
|
||||
"]",
|
||||
],
|
||||
),
|
||||
]
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn lifetime_param_inlay_hint_has_location_link() {
|
||||
check_expect(
|
||||
InlayHintsConfig { type_hints: true, ..DISABLED_CONFIG },
|
||||
r#"
|
||||
struct S<'lt>(*mut &'lt ());
|
||||
|
||||
fn f<'a>() {
|
||||
let x = S::<'a>(loop {});
|
||||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
[
|
||||
(
|
||||
51..52,
|
||||
[
|
||||
InlayHintLabelPart {
|
||||
text: "S",
|
||||
linked_location: Some(
|
||||
Computed(
|
||||
FileRangeWrapper {
|
||||
file_id: FileId(
|
||||
0,
|
||||
),
|
||||
range: 7..8,
|
||||
},
|
||||
),
|
||||
),
|
||||
tooltip: "",
|
||||
},
|
||||
"<",
|
||||
InlayHintLabelPart {
|
||||
text: "'a",
|
||||
linked_location: Some(
|
||||
Computed(
|
||||
FileRangeWrapper {
|
||||
file_id: FileId(
|
||||
0,
|
||||
),
|
||||
range: 35..37,
|
||||
},
|
||||
),
|
||||
),
|
||||
tooltip: "",
|
||||
},
|
||||
">",
|
||||
],
|
||||
),
|
||||
]
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -143,7 +143,7 @@ fn foo<T>() {}
|
||||
file_id: FileId(
|
||||
1,
|
||||
),
|
||||
range: 446..451,
|
||||
range: 470..475,
|
||||
},
|
||||
),
|
||||
),
|
||||
|
||||
@@ -38,7 +38,8 @@
|
||||
};
|
||||
|
||||
use crate::{
|
||||
Analysis, FilePosition, HighlightedRange, NavigationTarget, TryToNav, highlight_related,
|
||||
Analysis, FilePosition, HighlightedRange, NavigationTarget, TryToNav,
|
||||
doc_links::token_as_doc_comment, highlight_related,
|
||||
};
|
||||
|
||||
/// Result of a reference search operation.
|
||||
@@ -211,6 +212,13 @@ pub(crate) fn find_defs(
|
||||
syntax: &SyntaxNode,
|
||||
offset: TextSize,
|
||||
) -> Option<Vec<Definition>> {
|
||||
if let Some(token) = syntax.token_at_offset(offset).left_biased()
|
||||
&& let Some(doc_comment) = token_as_doc_comment(&token)
|
||||
{
|
||||
return doc_comment
|
||||
.get_definition_with_descend_at(sema, offset, |def, _, _| Some(vec![def]));
|
||||
}
|
||||
|
||||
let token = syntax.token_at_offset(offset).find(|t| {
|
||||
matches!(
|
||||
t.kind(),
|
||||
@@ -785,6 +793,23 @@ fn main() {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_find_all_refs_in_comments() {
|
||||
check(
|
||||
r#"
|
||||
struct Foo;
|
||||
|
||||
/// $0[`Foo`] is just above
|
||||
struct Bar;
|
||||
"#,
|
||||
expect![[r#"
|
||||
Foo Struct FileId(0) 0..11 7..10
|
||||
|
||||
(no references)
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn search_filters_by_range() {
|
||||
check(
|
||||
|
||||
@@ -334,7 +334,7 @@ pub const fn new() -> Self {
|
||||
|
||||
impl<T: Internable + ?Sized> InternStorage<T> {
|
||||
pub(crate) fn get(&self) -> &InternMap<T> {
|
||||
self.map.get_or_init(DashMap::default)
|
||||
self.map.get_or_init(|| DashMap::with_capacity_and_hasher(1024, Default::default()))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -292,7 +292,12 @@ pub const fn new() -> Self {
|
||||
|
||||
impl<T: SliceInternable> InternSliceStorage<T> {
|
||||
pub(crate) fn get(&self) -> &InternMap<T> {
|
||||
self.map.get_or_init(DashMap::default)
|
||||
self.map.get_or_init(|| {
|
||||
DashMap::with_capacity_and_hasher(
|
||||
(64 * 1024) / std::mem::size_of::<T::SliceType>(),
|
||||
Default::default(),
|
||||
)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -297,6 +297,7 @@ pub(super) fn prefill() -> DashMap<Symbol, (), BuildHasherDefault<FxHasher>> {
|
||||
iterator,
|
||||
keyword,
|
||||
lang,
|
||||
lang_items,
|
||||
le,
|
||||
Left,
|
||||
len,
|
||||
|
||||
@@ -11,15 +11,16 @@
|
||||
use std::{any::Any, collections::hash_map::Entry, mem, path::Path, sync};
|
||||
|
||||
use crossbeam_channel::{Receiver, unbounded};
|
||||
use hir_expand::proc_macro::{
|
||||
ProcMacro, ProcMacroExpander, ProcMacroExpansionError, ProcMacroKind, ProcMacroLoadResult,
|
||||
ProcMacrosBuilder,
|
||||
use hir_expand::{
|
||||
db::ExpandDatabase,
|
||||
proc_macro::{
|
||||
ProcMacro, ProcMacroExpander, ProcMacroExpansionError, ProcMacroKind, ProcMacroLoadResult,
|
||||
ProcMacrosBuilder,
|
||||
},
|
||||
};
|
||||
use ide_db::{
|
||||
ChangeWithProcMacros, FxHashMap, RootDatabase,
|
||||
base_db::{
|
||||
CrateGraphBuilder, Env, ProcMacroLoadingError, SourceDatabase, SourceRoot, SourceRootId,
|
||||
},
|
||||
base_db::{CrateGraphBuilder, Env, ProcMacroLoadingError, SourceRoot, SourceRootId},
|
||||
prime_caches,
|
||||
};
|
||||
use itertools::Itertools;
|
||||
@@ -31,7 +32,8 @@
|
||||
},
|
||||
};
|
||||
use project_model::{CargoConfig, PackageRoot, ProjectManifest, ProjectWorkspace};
|
||||
use span::Span;
|
||||
use span::{Span, SpanAnchor, SyntaxContext};
|
||||
use tt::{TextRange, TextSize};
|
||||
use vfs::{
|
||||
AbsPath, AbsPathBuf, FileId, VfsPath,
|
||||
file_set::FileSetConfig,
|
||||
@@ -530,7 +532,7 @@ fn expander_to_proc_macro(
|
||||
impl ProcMacroExpander for Expander {
|
||||
fn expand(
|
||||
&self,
|
||||
db: &dyn SourceDatabase,
|
||||
db: &dyn ExpandDatabase,
|
||||
subtree: &tt::TopSubtree,
|
||||
attrs: Option<&tt::TopSubtree>,
|
||||
env: &Env,
|
||||
@@ -540,11 +542,44 @@ fn expand(
|
||||
current_dir: String,
|
||||
) -> Result<tt::TopSubtree, ProcMacroExpansionError> {
|
||||
let mut cb = |req| match req {
|
||||
SubRequest::SourceText { file_id, start, end } => {
|
||||
let file = FileId::from_raw(file_id);
|
||||
let text = db.file_text(file).text(db);
|
||||
let slice = text.get(start as usize..end as usize).map(ToOwned::to_owned);
|
||||
Ok(SubResponse::SourceTextResult { text: slice })
|
||||
SubRequest::LocalFilePath { file_id } => {
|
||||
let file_id = FileId::from_raw(file_id);
|
||||
let source_root_id = db.file_source_root(file_id).source_root_id(db);
|
||||
let source_root = db.source_root(source_root_id).source_root(db);
|
||||
let name = source_root
|
||||
.path_for_file(&file_id)
|
||||
.and_then(|path| path.as_path())
|
||||
.map(|path| path.to_string());
|
||||
|
||||
Ok(SubResponse::LocalFilePathResult { name })
|
||||
}
|
||||
SubRequest::SourceText { file_id, ast_id, start, end } => {
|
||||
let ast_id = span::ErasedFileAstId::from_raw(ast_id);
|
||||
let editioned_file_id = span::EditionedFileId::from_raw(file_id);
|
||||
let span = Span {
|
||||
range: TextRange::new(TextSize::from(start), TextSize::from(end)),
|
||||
anchor: SpanAnchor { file_id: editioned_file_id, ast_id },
|
||||
ctx: SyntaxContext::root(editioned_file_id.edition()),
|
||||
};
|
||||
let range = db.resolve_span(span);
|
||||
let source = db.file_text(range.file_id.file_id(db)).text(db);
|
||||
let text = source
|
||||
.get(usize::from(range.range.start())..usize::from(range.range.end()))
|
||||
.map(ToOwned::to_owned);
|
||||
|
||||
Ok(SubResponse::SourceTextResult { text })
|
||||
}
|
||||
SubRequest::FilePath { file_id } => {
|
||||
let file_id = FileId::from_raw(file_id);
|
||||
let source_root_id = db.file_source_root(file_id).source_root_id(db);
|
||||
let source_root = db.source_root(source_root_id).source_root(db);
|
||||
let name = source_root
|
||||
.path_for_file(&file_id)
|
||||
.and_then(|path| path.as_path())
|
||||
.map(|path| path.to_string())
|
||||
.unwrap_or_default();
|
||||
|
||||
Ok(SubResponse::FilePathResult { name })
|
||||
}
|
||||
};
|
||||
match self.0.expand(
|
||||
|
||||
@@ -10,12 +10,16 @@
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub enum SubRequest {
|
||||
SourceText { file_id: u32, start: u32, end: u32 },
|
||||
FilePath { file_id: u32 },
|
||||
SourceText { file_id: u32, ast_id: u32, start: u32, end: u32 },
|
||||
LocalFilePath { file_id: u32 },
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub enum SubResponse {
|
||||
FilePathResult { name: String },
|
||||
SourceTextResult { text: Option<String> },
|
||||
LocalFilePathResult { name: Option<String> },
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
|
||||
@@ -18,6 +18,7 @@ clap = {version = "4.5.42", default-features = false, features = ["std"]}
|
||||
|
||||
[features]
|
||||
default = []
|
||||
# default = ["sysroot-abi"]
|
||||
sysroot-abi = ["proc-macro-srv/sysroot-abi", "proc-macro-api/sysroot-abi"]
|
||||
in-rust-tree = ["proc-macro-srv/in-rust-tree", "sysroot-abi"]
|
||||
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
# proc-macro-srv-cli
|
||||
|
||||
A standalone binary for the `proc-macro-srv` crate that provides procedural macro expansion for rust-analyzer.
|
||||
|
||||
## Overview
|
||||
|
||||
rust-analyzer uses a RPC (via stdio) client-server architecture for procedural macro expansion. This is necessary because:
|
||||
|
||||
1. Proc macros are dynamic libraries that can segfault, bringing down the entire process, so running them out of process allows rust-analyzer to recover from fatal errors.
|
||||
2. Proc macro dylibs are compiled against a specific rustc version and require matching internal APIs to load and execute, as such having this binary shipped as a rustup component allows us to always match the rustc version irrespective of the rust-analyzer version used.
|
||||
|
||||
## The `sysroot-abi` Feature
|
||||
|
||||
**The `sysroot-abi` feature is required for the binary to actually function.** Without it, the binary will return an error:
|
||||
|
||||
```
|
||||
proc-macro-srv-cli needs to be compiled with the `sysroot-abi` feature to function
|
||||
```
|
||||
|
||||
This feature is necessary because the proc-macro server needs access to unstable rustc internals (`proc_macro_internals`, `proc_macro_diagnostic`, `proc_macro_span`) which are only available on nightly or with `RUSTC_BOOTSTRAP=1`.
|
||||
rust-analyzer is a stable toolchain project though, so the feature flag is used to have it remain compilable on stable by default.
|
||||
|
||||
### Building
|
||||
|
||||
```bash
|
||||
# Using nightly toolchain
|
||||
cargo build -p proc-macro-srv-cli --features sysroot-abi
|
||||
|
||||
# Or with RUSTC_BOOTSTRAP on stable
|
||||
RUSTC_BOOTSTRAP=1 cargo build -p proc-macro-srv-cli --features sysroot-abi
|
||||
```
|
||||
|
||||
### Installing the proc-macro server
|
||||
|
||||
For local testing purposes, you can install the proc-macro server using the xtask command:
|
||||
|
||||
```bash
|
||||
# Recommended: use the xtask command
|
||||
cargo xtask install --proc-macro-server
|
||||
```
|
||||
|
||||
## Testing
|
||||
|
||||
```bash
|
||||
cargo test --features sysroot-abi -p proc-macro-srv -p proc-macro-srv-cli -p proc-macro-api
|
||||
```
|
||||
|
||||
The tests use a test proc macro dylib built by the `proc-macro-test` crate, which compiles a small proc macro implementation during build time.
|
||||
|
||||
**Note**: Tests only compile on nightly toolchains (or with `RUSTC_BOOTSTRAP=1`).
|
||||
|
||||
## Usage
|
||||
|
||||
The binary requires the `RUST_ANALYZER_INTERNALS_DO_NOT_USE` environment variable to be set. This is intentional—the binary is an implementation detail of rust-analyzer and its API is still unstable:
|
||||
|
||||
```bash
|
||||
RUST_ANALYZER_INTERNALS_DO_NOT_USE=1 rust-analyzer-proc-macro-srv --version
|
||||
```
|
||||
|
||||
## Related Crates
|
||||
|
||||
- `proc-macro-srv`: The core server library that handles loading dylibs and expanding macros, but not the RPC protocol.
|
||||
- `proc-macro-api`: The client library used by rust-analyzer to communicate with this server as well as the protocol definitions.
|
||||
- `proc-macro-test`: Test harness with sample proc macros for testing
|
||||
- `proc-macro-srv-cli`: The actual server binary that handles the RPC protocol.
|
||||
@@ -81,7 +81,6 @@ fn macro_kind_to_api(kind: proc_macro_srv::ProcMacroKind) -> proc_macro_api::Pro
|
||||
}
|
||||
|
||||
bidirectional::Request::ApiVersionCheck {} => {
|
||||
// bidirectional::Response::ApiVersionCheck(CURRENT_API_VERSION).write::<_, C>(stdout)
|
||||
send_response::<C>(
|
||||
&stdout,
|
||||
bidirectional::Response::ApiVersionCheck(CURRENT_API_VERSION),
|
||||
@@ -167,28 +166,57 @@ struct ProcMacroClientHandle<'a, C: Codec> {
|
||||
buf: &'a mut C::Buf,
|
||||
}
|
||||
|
||||
impl<C: Codec> proc_macro_srv::ProcMacroClientInterface for ProcMacroClientHandle<'_, C> {
|
||||
fn source_text(&mut self, file_id: u32, start: u32, end: u32) -> Option<String> {
|
||||
let req = bidirectional::BidirectionalMessage::SubRequest(
|
||||
bidirectional::SubRequest::SourceText { file_id, start, end },
|
||||
);
|
||||
impl<'a, C: Codec> ProcMacroClientHandle<'a, C> {
|
||||
fn roundtrip(
|
||||
&mut self,
|
||||
req: bidirectional::SubRequest,
|
||||
) -> Option<bidirectional::BidirectionalMessage> {
|
||||
let msg = bidirectional::BidirectionalMessage::SubRequest(req);
|
||||
|
||||
if req.write::<_, C>(&mut self.stdout.lock()).is_err() {
|
||||
if msg.write::<_, C>(&mut self.stdout.lock()).is_err() {
|
||||
return None;
|
||||
}
|
||||
|
||||
let msg = match bidirectional::BidirectionalMessage::read::<_, C>(
|
||||
&mut self.stdin.lock(),
|
||||
self.buf,
|
||||
) {
|
||||
Ok(Some(msg)) => msg,
|
||||
_ => return None,
|
||||
};
|
||||
match bidirectional::BidirectionalMessage::read::<_, C>(&mut self.stdin.lock(), self.buf) {
|
||||
Ok(Some(msg)) => Some(msg),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
match msg {
|
||||
bidirectional::BidirectionalMessage::SubResponse(
|
||||
impl<C: Codec> proc_macro_srv::ProcMacroClientInterface for ProcMacroClientHandle<'_, C> {
|
||||
fn file(&mut self, file_id: proc_macro_srv::span::FileId) -> String {
|
||||
match self.roundtrip(bidirectional::SubRequest::FilePath { file_id: file_id.index() }) {
|
||||
Some(bidirectional::BidirectionalMessage::SubResponse(
|
||||
bidirectional::SubResponse::FilePathResult { name },
|
||||
)) => name,
|
||||
_ => String::new(),
|
||||
}
|
||||
}
|
||||
|
||||
fn source_text(
|
||||
&mut self,
|
||||
proc_macro_srv::span::Span { range, anchor, ctx: _ }: proc_macro_srv::span::Span,
|
||||
) -> Option<String> {
|
||||
match self.roundtrip(bidirectional::SubRequest::SourceText {
|
||||
file_id: anchor.file_id.as_u32(),
|
||||
ast_id: anchor.ast_id.into_raw(),
|
||||
start: range.start().into(),
|
||||
end: range.end().into(),
|
||||
}) {
|
||||
Some(bidirectional::BidirectionalMessage::SubResponse(
|
||||
bidirectional::SubResponse::SourceTextResult { text },
|
||||
) => text,
|
||||
)) => text,
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn local_file(&mut self, file_id: proc_macro_srv::span::FileId) -> Option<String> {
|
||||
match self.roundtrip(bidirectional::SubRequest::LocalFilePath { file_id: file_id.index() })
|
||||
{
|
||||
Some(bidirectional::BidirectionalMessage::SubResponse(
|
||||
bidirectional::SubResponse::LocalFilePathResult { name },
|
||||
)) => name,
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -53,6 +53,7 @@
|
||||
pub use crate::server_impl::token_id::SpanId;
|
||||
|
||||
pub use proc_macro::Delimiter;
|
||||
pub use span;
|
||||
|
||||
pub use crate::bridge::*;
|
||||
pub use crate::server_impl::literal_from_str;
|
||||
@@ -94,7 +95,9 @@ pub fn join_spans(&self, first: Span, second: Span) -> Option<Span> {
|
||||
pub type ProcMacroClientHandle<'a> = &'a mut (dyn ProcMacroClientInterface + Sync + Send);
|
||||
|
||||
pub trait ProcMacroClientInterface {
|
||||
fn source_text(&mut self, file_id: u32, start: u32, end: u32) -> Option<String>;
|
||||
fn file(&mut self, file_id: span::FileId) -> String;
|
||||
fn source_text(&mut self, span: Span) -> Option<String>;
|
||||
fn local_file(&mut self, file_id: span::FileId) -> Option<String>;
|
||||
}
|
||||
|
||||
const EXPANDER_STACK_SIZE: usize = 8 * 1024 * 1024;
|
||||
|
||||
+5
-11
@@ -127,13 +127,11 @@ impl server::Span for RaSpanServer<'_> {
|
||||
fn debug(&mut self, span: Self::Span) -> String {
|
||||
format!("{:?}", span)
|
||||
}
|
||||
fn file(&mut self, _: Self::Span) -> String {
|
||||
// FIXME
|
||||
String::new()
|
||||
fn file(&mut self, span: Self::Span) -> String {
|
||||
self.callback.as_mut().map(|cb| cb.file(span.anchor.file_id.file_id())).unwrap_or_default()
|
||||
}
|
||||
fn local_file(&mut self, _: Self::Span) -> Option<String> {
|
||||
// FIXME
|
||||
None
|
||||
fn local_file(&mut self, span: Self::Span) -> Option<String> {
|
||||
self.callback.as_mut().and_then(|cb| cb.local_file(span.anchor.file_id.file_id()))
|
||||
}
|
||||
fn save_span(&mut self, _span: Self::Span) -> usize {
|
||||
// FIXME, quote is incompatible with third-party tools
|
||||
@@ -152,11 +150,7 @@ fn recover_proc_macro_span(&mut self, _id: usize) -> Self::Span {
|
||||
/// See PR:
|
||||
/// https://github.com/rust-lang/rust/pull/55780
|
||||
fn source_text(&mut self, span: Self::Span) -> Option<String> {
|
||||
let file_id = span.anchor.file_id;
|
||||
let start: u32 = span.range.start().into();
|
||||
let end: u32 = span.range.end().into();
|
||||
|
||||
self.callback.as_mut()?.source_text(file_id.file_id().index(), start, end)
|
||||
self.callback.as_mut()?.source_text(span)
|
||||
}
|
||||
|
||||
fn parent(&mut self, _span: Self::Span) -> Option<Self::Span> {
|
||||
|
||||
@@ -16,6 +16,9 @@
|
||||
|
||||
extern crate ra_ap_rustc_type_ir as rustc_type_ir;
|
||||
|
||||
/*
|
||||
If you bump this, grep for `FIXME(MINIMUM_SUPPORTED_TOOLCHAIN_VERSION)` to check for old support code we can drop
|
||||
*/
|
||||
/// Any toolchain less than this version will likely not work with rust-analyzer built from this revision.
|
||||
pub const MINIMUM_SUPPORTED_TOOLCHAIN_VERSION: semver::Version = semver::Version {
|
||||
major: 1,
|
||||
|
||||
@@ -19,9 +19,8 @@
|
||||
//! # The Call-site Hierarchy
|
||||
//!
|
||||
//! `ExpnData::call_site` in rustc, [`MacroCallLoc::call_site`] in rust-analyzer.
|
||||
use std::fmt;
|
||||
|
||||
use crate::Edition;
|
||||
use std::fmt;
|
||||
|
||||
/// A syntax context describes a hierarchy tracking order of macro definitions.
|
||||
#[cfg(feature = "salsa")]
|
||||
|
||||
@@ -738,7 +738,7 @@ fn parse_crate(
|
||||
impl ProcMacroExpander for IdentityProcMacroExpander {
|
||||
fn expand(
|
||||
&self,
|
||||
_: &dyn SourceDatabase,
|
||||
_: &dyn ExpandDatabase,
|
||||
subtree: &TopSubtree,
|
||||
_: Option<&TopSubtree>,
|
||||
_: &Env,
|
||||
@@ -761,7 +761,7 @@ fn eq_dyn(&self, other: &dyn ProcMacroExpander) -> bool {
|
||||
impl ProcMacroExpander for Issue18089ProcMacroExpander {
|
||||
fn expand(
|
||||
&self,
|
||||
_: &dyn SourceDatabase,
|
||||
_: &dyn ExpandDatabase,
|
||||
subtree: &TopSubtree,
|
||||
_: Option<&TopSubtree>,
|
||||
_: &Env,
|
||||
@@ -797,7 +797,7 @@ fn eq_dyn(&self, other: &dyn ProcMacroExpander) -> bool {
|
||||
impl ProcMacroExpander for AttributeInputReplaceProcMacroExpander {
|
||||
fn expand(
|
||||
&self,
|
||||
_: &dyn SourceDatabase,
|
||||
_: &dyn ExpandDatabase,
|
||||
_: &TopSubtree,
|
||||
attrs: Option<&TopSubtree>,
|
||||
_: &Env,
|
||||
@@ -821,7 +821,7 @@ fn eq_dyn(&self, other: &dyn ProcMacroExpander) -> bool {
|
||||
impl ProcMacroExpander for Issue18840ProcMacroExpander {
|
||||
fn expand(
|
||||
&self,
|
||||
_: &dyn SourceDatabase,
|
||||
_: &dyn ExpandDatabase,
|
||||
fn_: &TopSubtree,
|
||||
_: Option<&TopSubtree>,
|
||||
_: &Env,
|
||||
@@ -858,7 +858,7 @@ fn eq_dyn(&self, other: &dyn ProcMacroExpander) -> bool {
|
||||
impl ProcMacroExpander for MirrorProcMacroExpander {
|
||||
fn expand(
|
||||
&self,
|
||||
_: &dyn SourceDatabase,
|
||||
_: &dyn ExpandDatabase,
|
||||
input: &TopSubtree,
|
||||
_: Option<&TopSubtree>,
|
||||
_: &Env,
|
||||
@@ -897,7 +897,7 @@ fn eq_dyn(&self, other: &dyn ProcMacroExpander) -> bool {
|
||||
impl ProcMacroExpander for ShortenProcMacroExpander {
|
||||
fn expand(
|
||||
&self,
|
||||
_: &dyn SourceDatabase,
|
||||
_: &dyn ExpandDatabase,
|
||||
input: &TopSubtree,
|
||||
_: Option<&TopSubtree>,
|
||||
_: &Env,
|
||||
@@ -942,7 +942,7 @@ fn eq_dyn(&self, other: &dyn ProcMacroExpander) -> bool {
|
||||
impl ProcMacroExpander for Issue17479ProcMacroExpander {
|
||||
fn expand(
|
||||
&self,
|
||||
_: &dyn SourceDatabase,
|
||||
_: &dyn ExpandDatabase,
|
||||
subtree: &TopSubtree,
|
||||
_: Option<&TopSubtree>,
|
||||
_: &Env,
|
||||
@@ -973,7 +973,7 @@ fn eq_dyn(&self, other: &dyn ProcMacroExpander) -> bool {
|
||||
impl ProcMacroExpander for Issue18898ProcMacroExpander {
|
||||
fn expand(
|
||||
&self,
|
||||
_: &dyn SourceDatabase,
|
||||
_: &dyn ExpandDatabase,
|
||||
subtree: &TopSubtree,
|
||||
_: Option<&TopSubtree>,
|
||||
_: &Env,
|
||||
@@ -1027,7 +1027,7 @@ fn eq_dyn(&self, other: &dyn ProcMacroExpander) -> bool {
|
||||
impl ProcMacroExpander for DisallowCfgProcMacroExpander {
|
||||
fn expand(
|
||||
&self,
|
||||
_: &dyn SourceDatabase,
|
||||
_: &dyn ExpandDatabase,
|
||||
subtree: &TopSubtree,
|
||||
_: Option<&TopSubtree>,
|
||||
_: &Env,
|
||||
@@ -1059,7 +1059,7 @@ fn eq_dyn(&self, other: &dyn ProcMacroExpander) -> bool {
|
||||
impl ProcMacroExpander for GenerateSuffixedTypeProcMacroExpander {
|
||||
fn expand(
|
||||
&self,
|
||||
_: &dyn SourceDatabase,
|
||||
_: &dyn ExpandDatabase,
|
||||
subtree: &TopSubtree,
|
||||
_attrs: Option<&TopSubtree>,
|
||||
_env: &Env,
|
||||
|
||||
@@ -80,6 +80,7 @@
|
||||
//! offset_of:
|
||||
|
||||
#![rustc_coherence_is_core]
|
||||
#![feature(lang_items)]
|
||||
|
||||
pub mod marker {
|
||||
// region:sized
|
||||
|
||||
+3
-3
@@ -5584,9 +5584,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/qs": {
|
||||
"version": "6.14.0",
|
||||
"resolved": "https://registry.npmjs.org/qs/-/qs-6.14.0.tgz",
|
||||
"integrity": "sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==",
|
||||
"version": "6.14.1",
|
||||
"resolved": "https://registry.npmjs.org/qs/-/qs-6.14.1.tgz",
|
||||
"integrity": "sha512-4EK3+xJl8Ts67nLYNwqw/dsFVnCf+qR7RgXSK9jEEm9unao3njwMDdmsdvoKBKHzxd7tCYz5e5M+SnMjdtXGQQ==",
|
||||
"dev": true,
|
||||
"license": "BSD-3-Clause",
|
||||
"dependencies": {
|
||||
|
||||
Reference in New Issue
Block a user