mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-09-27 04:19:13 +00:00
Merge commit '21b06c1beb
' into sync-from-ra
This commit is contained in:
parent
cac74d98f6
commit
e37cf75791
59 changed files with 1080 additions and 477 deletions
|
@ -2,7 +2,7 @@
|
|||
//!
|
||||
//! The actual definitions were copied from rustc's `compiler/rustc_feature/src/builtin_attrs.rs`.
|
||||
//!
|
||||
//! It was last synchronized with upstream commit e29821ff85a2a3000d226f99f62f89464028d5d6.
|
||||
//! It was last synchronized with upstream commit c3def263a44e07e09ae6d57abfc8650227fb4972.
|
||||
//!
|
||||
//! The macros were adjusted to only expand to the attribute name, since that is all we need to do
|
||||
//! name resolution, and `BUILTIN_ATTRIBUTES` is almost entirely unchanged from the original, to
|
||||
|
@ -240,7 +240,7 @@ pub const INERT_ATTRIBUTES: &[BuiltinAttribute] = &[
|
|||
template!(List: "address, kcfi, memory, thread"), DuplicatesOk,
|
||||
experimental!(no_sanitize)
|
||||
),
|
||||
gated!(coverage, Normal, template!(Word, List: "on|off"), WarnFollowing, experimental!(coverage)),
|
||||
gated!(coverage, Normal, template!(Word, List: "on|off"), WarnFollowing, coverage_attribute, experimental!(coverage)),
|
||||
|
||||
ungated!(
|
||||
doc, Normal, template!(List: "hidden|inline|...", NameValueStr: "string"), DuplicatesOk
|
||||
|
@ -364,7 +364,6 @@ pub const INERT_ATTRIBUTES: &[BuiltinAttribute] = &[
|
|||
allow_internal_unsafe, Normal, template!(Word), WarnFollowing,
|
||||
"allow_internal_unsafe side-steps the unsafe_code lint",
|
||||
),
|
||||
ungated!(rustc_safe_intrinsic, Normal, template!(Word), DuplicatesOk),
|
||||
rustc_attr!(rustc_allowed_through_unstable_modules, Normal, template!(Word), WarnFollowing,
|
||||
"rustc_allowed_through_unstable_modules special cases accidental stabilizations of stable items \
|
||||
through unstable paths"),
|
||||
|
@ -453,6 +452,12 @@ pub const INERT_ATTRIBUTES: &[BuiltinAttribute] = &[
|
|||
ErrorFollowing,
|
||||
INTERNAL_UNSTABLE
|
||||
),
|
||||
rustc_attr!(
|
||||
rustc_confusables, Normal,
|
||||
template!(List: r#""name1", "name2", ..."#),
|
||||
ErrorFollowing,
|
||||
INTERNAL_UNSTABLE,
|
||||
),
|
||||
// Enumerates "identity-like" conversion methods to suggest on type mismatch.
|
||||
rustc_attr!(
|
||||
rustc_conversion_suggestion, Normal, template!(Word), WarnFollowing, INTERNAL_UNSTABLE
|
||||
|
@ -488,6 +493,10 @@ pub const INERT_ATTRIBUTES: &[BuiltinAttribute] = &[
|
|||
rustc_attr!(
|
||||
rustc_do_not_const_check, Normal, template!(Word), WarnFollowing, INTERNAL_UNSTABLE
|
||||
),
|
||||
// Ensure the argument to this function is &&str during const-check.
|
||||
rustc_attr!(
|
||||
rustc_const_panic_str, Normal, template!(Word), WarnFollowing, INTERNAL_UNSTABLE
|
||||
),
|
||||
|
||||
// ==========================================================================
|
||||
// Internal attributes, Layout related:
|
||||
|
@ -520,6 +529,10 @@ pub const INERT_ATTRIBUTES: &[BuiltinAttribute] = &[
|
|||
rustc_pass_by_value, Normal, template!(Word), ErrorFollowing,
|
||||
"#[rustc_pass_by_value] is used to mark types that must be passed by value instead of reference."
|
||||
),
|
||||
rustc_attr!(
|
||||
rustc_never_returns_null_ptr, Normal, template!(Word), ErrorFollowing,
|
||||
"#[rustc_never_returns_null_ptr] is used to mark functions returning non-null pointers."
|
||||
),
|
||||
rustc_attr!(
|
||||
rustc_coherence_is_core, AttributeType::CrateLevel, template!(Word), ErrorFollowing, @only_local: true,
|
||||
"#![rustc_coherence_is_core] allows inherent methods on builtin types, only intended to be used in `core`."
|
||||
|
@ -533,7 +546,11 @@ pub const INERT_ATTRIBUTES: &[BuiltinAttribute] = &[
|
|||
"#[rustc_allow_incoherent_impl] has to be added to all impl items of an incoherent inherent impl."
|
||||
),
|
||||
rustc_attr!(
|
||||
rustc_deny_explicit_impl, AttributeType::Normal, template!(Word), ErrorFollowing, @only_local: false,
|
||||
rustc_deny_explicit_impl,
|
||||
AttributeType::Normal,
|
||||
template!(List: "implement_via_object = (true|false)"),
|
||||
ErrorFollowing,
|
||||
@only_local: true,
|
||||
"#[rustc_deny_explicit_impl] enforces that a trait can have no user-provided impls"
|
||||
),
|
||||
rustc_attr!(
|
||||
|
@ -614,6 +631,10 @@ pub const INERT_ATTRIBUTES: &[BuiltinAttribute] = &[
|
|||
rustc_doc_primitive, Normal, template!(NameValueStr: "primitive name"), ErrorFollowing,
|
||||
r#"`rustc_doc_primitive` is a rustc internal attribute"#,
|
||||
),
|
||||
rustc_attr!(
|
||||
rustc_safe_intrinsic, Normal, template!(Word), WarnFollowing,
|
||||
"the `#[rustc_safe_intrinsic]` attribute is used internally to mark intrinsics as safe"
|
||||
),
|
||||
|
||||
// ==========================================================================
|
||||
// Internal attributes, Testing:
|
||||
|
@ -625,13 +646,16 @@ pub const INERT_ATTRIBUTES: &[BuiltinAttribute] = &[
|
|||
rustc_attr!(TEST, rustc_insignificant_dtor, Normal, template!(Word), WarnFollowing),
|
||||
rustc_attr!(TEST, rustc_strict_coherence, Normal, template!(Word), WarnFollowing),
|
||||
rustc_attr!(TEST, rustc_variance, Normal, template!(Word), WarnFollowing),
|
||||
rustc_attr!(TEST, rustc_variance_of_opaques, Normal, template!(Word), WarnFollowing),
|
||||
rustc_attr!(TEST, rustc_hidden_type_of_opaques, Normal, template!(Word), WarnFollowing),
|
||||
rustc_attr!(TEST, rustc_layout, Normal, template!(List: "field1, field2, ..."), WarnFollowing),
|
||||
rustc_attr!(TEST, rustc_abi, Normal, template!(List: "field1, field2, ..."), WarnFollowing),
|
||||
rustc_attr!(TEST, rustc_regions, Normal, template!(Word), WarnFollowing),
|
||||
rustc_attr!(
|
||||
TEST, rustc_error, Normal,
|
||||
template!(Word, List: "span_delayed_bug_from_inside_query"), WarnFollowingWordOnly
|
||||
),
|
||||
rustc_attr!(TEST, rustc_dump_user_substs, Normal, template!(Word), WarnFollowing),
|
||||
rustc_attr!(TEST, rustc_dump_user_args, Normal, template!(Word), WarnFollowing),
|
||||
rustc_attr!(TEST, rustc_evaluate_where_clauses, Normal, template!(Word), WarnFollowing),
|
||||
rustc_attr!(
|
||||
TEST, rustc_if_this_changed, Normal, template!(Word, List: "DepNode"), DuplicatesOk
|
||||
|
|
|
@ -5,8 +5,7 @@
|
|||
//! node for a *child*, and get its hir.
|
||||
|
||||
use either::Either;
|
||||
use hir_expand::HirFileId;
|
||||
use syntax::ast::HasDocComments;
|
||||
use hir_expand::{attrs::collect_attrs, HirFileId};
|
||||
|
||||
use crate::{
|
||||
db::DefDatabase,
|
||||
|
@ -118,8 +117,8 @@ impl ChildBySource for ItemScope {
|
|||
|(ast_id, calls)| {
|
||||
let adt = ast_id.to_node(db.upcast());
|
||||
calls.for_each(|(attr_id, call_id, calls)| {
|
||||
if let Some(Either::Left(attr)) =
|
||||
adt.doc_comments_and_attrs().nth(attr_id.ast_index())
|
||||
if let Some((_, Either::Left(attr))) =
|
||||
collect_attrs(&adt).nth(attr_id.ast_index())
|
||||
{
|
||||
res[keys::DERIVE_MACRO_CALL].insert(attr, (attr_id, call_id, calls.into()));
|
||||
}
|
||||
|
|
|
@ -222,11 +222,10 @@ impl GenericParams {
|
|||
let module = loc.container.module(db);
|
||||
let func_data = db.function_data(id);
|
||||
|
||||
// Don't create an `Expander` nor call `loc.source(db)` if not needed since this
|
||||
// causes a reparse after the `ItemTree` has been created.
|
||||
let mut expander = Lazy::new(|| {
|
||||
(module.def_map(db), Expander::new(db, loc.source(db).file_id, module))
|
||||
});
|
||||
// Don't create an `Expander` if not needed since this
|
||||
// could cause a reparse after the `ItemTree` has been created due to the spanmap.
|
||||
let mut expander =
|
||||
Lazy::new(|| (module.def_map(db), Expander::new(db, loc.id.file_id(), module)));
|
||||
for param in func_data.params.iter() {
|
||||
generic_params.fill_implicit_impl_trait_args(db, &mut expander, param);
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@ use indexmap::IndexMap;
|
|||
use itertools::Itertools;
|
||||
use rustc_hash::{FxHashSet, FxHasher};
|
||||
use smallvec::SmallVec;
|
||||
use stdx::format_to;
|
||||
use triomphe::Arc;
|
||||
|
||||
use crate::{
|
||||
|
@ -53,13 +54,25 @@ pub struct ImportMap {
|
|||
fst: fst::Map<Vec<u8>>,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq)]
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Ord, PartialOrd)]
|
||||
enum IsTraitAssocItem {
|
||||
Yes,
|
||||
No,
|
||||
}
|
||||
|
||||
impl ImportMap {
|
||||
pub fn dump(&self, db: &dyn DefDatabase) -> String {
|
||||
let mut out = String::new();
|
||||
for (k, v) in self.map.iter() {
|
||||
format_to!(out, "{:?} ({:?}) -> ", k, v.1);
|
||||
for v in &v.0 {
|
||||
format_to!(out, "{}:{:?}, ", v.name.display(db.upcast()), v.container);
|
||||
}
|
||||
format_to!(out, "\n");
|
||||
}
|
||||
out
|
||||
}
|
||||
|
||||
pub(crate) fn import_map_query(db: &dyn DefDatabase, krate: CrateId) -> Arc<Self> {
|
||||
let _p = profile::span("import_map_query");
|
||||
|
||||
|
@ -68,26 +81,31 @@ impl ImportMap {
|
|||
let mut importables: Vec<_> = map
|
||||
.iter()
|
||||
// We've only collected items, whose name cannot be tuple field.
|
||||
.flat_map(|(&item, (info, _))| {
|
||||
info.iter()
|
||||
.map(move |info| (item, info.name.as_str().unwrap().to_ascii_lowercase()))
|
||||
.flat_map(|(&item, (info, is_assoc))| {
|
||||
info.iter().map(move |info| {
|
||||
(item, *is_assoc, info.name.as_str().unwrap().to_ascii_lowercase())
|
||||
})
|
||||
})
|
||||
.collect();
|
||||
importables.sort_by(|(_, lhs_name), (_, rhs_name)| lhs_name.cmp(rhs_name));
|
||||
importables.sort_by(|(_, l_is_assoc, lhs_name), (_, r_is_assoc, rhs_name)| {
|
||||
lhs_name.cmp(rhs_name).then_with(|| l_is_assoc.cmp(r_is_assoc))
|
||||
});
|
||||
importables.dedup();
|
||||
|
||||
// Build the FST, taking care not to insert duplicate values.
|
||||
let mut builder = fst::MapBuilder::memory();
|
||||
let iter =
|
||||
importables.iter().enumerate().dedup_by(|(_, (_, lhs)), (_, (_, rhs))| lhs == rhs);
|
||||
for (start_idx, (_, name)) in iter {
|
||||
let iter = importables
|
||||
.iter()
|
||||
.enumerate()
|
||||
.dedup_by(|(_, (_, _, lhs)), (_, (_, _, rhs))| lhs == rhs);
|
||||
for (start_idx, (_, _, name)) in iter {
|
||||
let _ = builder.insert(name, start_idx as u64);
|
||||
}
|
||||
|
||||
Arc::new(ImportMap {
|
||||
map,
|
||||
fst: builder.into_map(),
|
||||
importables: importables.into_iter().map(|(item, _)| item).collect(),
|
||||
importables: importables.into_iter().map(|(item, _, _)| item).collect(),
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -328,20 +346,20 @@ impl Query {
|
|||
}
|
||||
|
||||
/// Checks whether the import map entry matches the query.
|
||||
fn import_matches(
|
||||
&self,
|
||||
db: &dyn DefDatabase,
|
||||
import: &ImportInfo,
|
||||
enforce_lowercase: bool,
|
||||
) -> bool {
|
||||
fn import_matches(&self, import: &ImportInfo, enforce_lowercase: bool) -> bool {
|
||||
let _p = profile::span("import_map::Query::import_matches");
|
||||
|
||||
// FIXME: Can we get rid of the alloc here?
|
||||
let mut input = import.name.display(db.upcast()).to_string();
|
||||
let input = import.name.to_smol_str();
|
||||
let mut _s_slot;
|
||||
let case_insensitive = enforce_lowercase || !self.case_sensitive;
|
||||
if case_insensitive {
|
||||
input.make_ascii_lowercase();
|
||||
}
|
||||
let input = if case_insensitive {
|
||||
_s_slot = String::from(input);
|
||||
_s_slot.make_ascii_lowercase();
|
||||
&*_s_slot
|
||||
} else {
|
||||
&*input
|
||||
};
|
||||
|
||||
let query_string = if case_insensitive { &self.lowercased } else { &self.query };
|
||||
|
||||
|
@ -351,7 +369,7 @@ impl Query {
|
|||
SearchMode::Fuzzy => {
|
||||
let mut input_chars = input.chars();
|
||||
for query_char in query_string.chars() {
|
||||
if input_chars.find(|&it| it == query_char).is_none() {
|
||||
if !input_chars.any(|it| it == query_char) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -372,6 +390,7 @@ pub fn search_dependencies(
|
|||
let _p = profile::span("search_dependencies").detail(|| format!("{query:?}"));
|
||||
|
||||
let graph = db.crate_graph();
|
||||
|
||||
let import_maps: Vec<_> =
|
||||
graph[krate].dependencies.iter().map(|dep| db.import_map(dep.crate_id)).collect();
|
||||
|
||||
|
@ -386,22 +405,23 @@ pub fn search_dependencies(
|
|||
|
||||
let mut res = FxHashSet::default();
|
||||
let mut common_importable_data_scratch = vec![];
|
||||
// FIXME: Improve this, its rather unreadable and does duplicate amount of work
|
||||
while let Some((_, indexed_values)) = stream.next() {
|
||||
for &IndexedValue { index, value } in indexed_values {
|
||||
let import_map = &import_maps[index];
|
||||
let importables @ [importable, ..] = &import_map.importables[value as usize..] else {
|
||||
continue;
|
||||
};
|
||||
|
||||
let &(ref importable_data, is_trait_assoc_item) = &import_map.map[importable];
|
||||
if !query.matches_assoc_mode(is_trait_assoc_item) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Fetch all the known names of this importable item (to handle import aliases/renames)
|
||||
common_importable_data_scratch.extend(
|
||||
importable_data
|
||||
.iter()
|
||||
.filter(|&info| query.import_matches(db, info, true))
|
||||
.filter(|&info| query.import_matches(info, true))
|
||||
// Name shared by the importable items in this group.
|
||||
.map(|info| info.name.to_smol_str()),
|
||||
);
|
||||
|
@ -415,6 +435,7 @@ pub fn search_dependencies(
|
|||
common_importable_data_scratch.drain(..).flat_map(|common_importable_name| {
|
||||
// Add the items from this name group. Those are all subsequent items in
|
||||
// `importables` whose name match `common_importable_name`.
|
||||
|
||||
importables
|
||||
.iter()
|
||||
.copied()
|
||||
|
@ -430,11 +451,8 @@ pub fn search_dependencies(
|
|||
.filter(move |item| {
|
||||
!query.case_sensitive || {
|
||||
// we've already checked the common importables name case-insensitively
|
||||
let &(ref import_infos, assoc_mode) = &import_map.map[item];
|
||||
query.matches_assoc_mode(assoc_mode)
|
||||
&& import_infos
|
||||
.iter()
|
||||
.any(|info| query.import_matches(db, info, false))
|
||||
let &(ref import_infos, _) = &import_map.map[item];
|
||||
import_infos.iter().any(|info| query.import_matches(info, false))
|
||||
}
|
||||
})
|
||||
});
|
||||
|
|
|
@ -106,11 +106,6 @@ impl ItemTree {
|
|||
pub(crate) fn file_item_tree_query(db: &dyn DefDatabase, file_id: HirFileId) -> Arc<ItemTree> {
|
||||
let _p = profile::span("file_item_tree_query").detail(|| format!("{file_id:?}"));
|
||||
let syntax = db.parse_or_expand(file_id);
|
||||
if never!(syntax.kind() == SyntaxKind::ERROR, "{:?} from {:?} {}", file_id, syntax, syntax)
|
||||
{
|
||||
// FIXME: not 100% sure why these crop up, but return an empty tree to avoid a panic
|
||||
return Default::default();
|
||||
}
|
||||
|
||||
let ctx = lower::Ctx::new(db, file_id);
|
||||
let mut top_attrs = None;
|
||||
|
@ -129,6 +124,9 @@ impl ItemTree {
|
|||
ctx.lower_macro_stmts(stmts)
|
||||
},
|
||||
_ => {
|
||||
if never!(syntax.kind() == SyntaxKind::ERROR, "{:?} from {:?} {}", file_id, syntax, syntax) {
|
||||
return Default::default();
|
||||
}
|
||||
panic!("cannot create item tree for file {file_id:?} from {syntax:?} {syntax}");
|
||||
},
|
||||
}
|
||||
|
|
|
@ -569,6 +569,8 @@ pub struct ConstBlockLoc {
|
|||
pub root: hir::ExprId,
|
||||
}
|
||||
|
||||
/// Something that holds types, required for the current const arg lowering implementation as they
|
||||
/// need to be able to query where they are defined.
|
||||
#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
|
||||
pub enum TypeOwnerId {
|
||||
FunctionId(FunctionId),
|
||||
|
@ -581,9 +583,6 @@ pub enum TypeOwnerId {
|
|||
TypeAliasId(TypeAliasId),
|
||||
ImplId(ImplId),
|
||||
EnumVariantId(EnumVariantId),
|
||||
// FIXME(const-generic-body): ModuleId should not be a type owner. This needs to be fixed to make `TypeOwnerId` actually
|
||||
// useful for assigning ids to in type consts.
|
||||
ModuleId(ModuleId),
|
||||
}
|
||||
|
||||
impl TypeOwnerId {
|
||||
|
@ -597,9 +596,7 @@ impl TypeOwnerId {
|
|||
TypeOwnerId::TypeAliasId(it) => GenericDefId::TypeAliasId(it),
|
||||
TypeOwnerId::ImplId(it) => GenericDefId::ImplId(it),
|
||||
TypeOwnerId::EnumVariantId(it) => GenericDefId::EnumVariantId(it),
|
||||
TypeOwnerId::InTypeConstId(_) | TypeOwnerId::ModuleId(_) | TypeOwnerId::StaticId(_) => {
|
||||
return None
|
||||
}
|
||||
TypeOwnerId::InTypeConstId(_) | TypeOwnerId::StaticId(_) => return None,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -614,8 +611,7 @@ impl_from!(
|
|||
TraitAliasId,
|
||||
TypeAliasId,
|
||||
ImplId,
|
||||
EnumVariantId,
|
||||
ModuleId
|
||||
EnumVariantId
|
||||
for TypeOwnerId
|
||||
);
|
||||
|
||||
|
@ -713,12 +709,15 @@ pub struct InTypeConstLoc {
|
|||
pub id: AstId<ast::ConstArg>,
|
||||
/// The thing this const arg appears in
|
||||
pub owner: TypeOwnerId,
|
||||
pub thing: Box<dyn OpaqueInternableThing>,
|
||||
// FIXME(const-generic-body): The expected type should not be
|
||||
pub expected_ty: Box<dyn OpaqueInternableThing>,
|
||||
}
|
||||
|
||||
impl PartialEq for InTypeConstLoc {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.id == other.id && self.owner == other.owner && &*self.thing == &*other.thing
|
||||
self.id == other.id
|
||||
&& self.owner == other.owner
|
||||
&& &*self.expected_ty == &*other.expected_ty
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1041,7 +1040,6 @@ impl HasModule for TypeOwnerId {
|
|||
TypeOwnerId::TypeAliasId(it) => it.lookup(db).module(db),
|
||||
TypeOwnerId::ImplId(it) => it.lookup(db).container,
|
||||
TypeOwnerId::EnumVariantId(it) => it.parent.lookup(db).container,
|
||||
TypeOwnerId::ModuleId(it) => *it,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,37 +13,97 @@ fn test_vec() {
|
|||
check(
|
||||
r#"
|
||||
macro_rules! vec {
|
||||
($($item:expr),*) => {{
|
||||
let mut v = Vec::new();
|
||||
$( v.push($item); )*
|
||||
v
|
||||
}};
|
||||
() => (
|
||||
$crate::__rust_force_expr!($crate::vec::Vec::new())
|
||||
);
|
||||
($elem:expr; $n:expr) => (
|
||||
$crate::__rust_force_expr!($crate::vec::from_elem($elem, $n))
|
||||
);
|
||||
($($x:expr),+ $(,)?) => (
|
||||
$crate::__rust_force_expr!(<[_]>::into_vec(
|
||||
// This rustc_box is not required, but it produces a dramatic improvement in compile
|
||||
// time when constructing arrays with many elements.
|
||||
#[rustc_box]
|
||||
$crate::boxed::Box::new([$($x),+])
|
||||
))
|
||||
);
|
||||
}
|
||||
|
||||
macro_rules! __rust_force_expr {
|
||||
($e:expr) => {
|
||||
$e
|
||||
};
|
||||
}
|
||||
|
||||
fn main() {
|
||||
vec!();
|
||||
vec![1u32,2];
|
||||
vec![a.];
|
||||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
macro_rules! vec {
|
||||
($($item:expr),*) => {{
|
||||
let mut v = Vec::new();
|
||||
$( v.push($item); )*
|
||||
v
|
||||
}};
|
||||
() => (
|
||||
$crate::__rust_force_expr!($crate::vec::Vec::new())
|
||||
);
|
||||
($elem:expr; $n:expr) => (
|
||||
$crate::__rust_force_expr!($crate::vec::from_elem($elem, $n))
|
||||
);
|
||||
($($x:expr),+ $(,)?) => (
|
||||
$crate::__rust_force_expr!(<[_]>::into_vec(
|
||||
// This rustc_box is not required, but it produces a dramatic improvement in compile
|
||||
// time when constructing arrays with many elements.
|
||||
#[rustc_box]
|
||||
$crate::boxed::Box::new([$($x),+])
|
||||
))
|
||||
);
|
||||
}
|
||||
|
||||
macro_rules! __rust_force_expr {
|
||||
($e:expr) => {
|
||||
$e
|
||||
};
|
||||
}
|
||||
|
||||
fn main() {
|
||||
{
|
||||
let mut v = Vec::new();
|
||||
v
|
||||
$crate::__rust_force_expr!($crate:: vec:: Vec:: new());
|
||||
$crate::__rust_force_expr!(<[_]>:: into_vec(#[rustc_box]$crate:: boxed:: Box:: new([1u32, 2])));
|
||||
/* error: expected Expr */$crate::__rust_force_expr!($crate:: vec:: from_elem((a.), $n));
|
||||
}
|
||||
"#]],
|
||||
);
|
||||
// FIXME we should ahev testing infra for multi level expansion tests
|
||||
check(
|
||||
r#"
|
||||
macro_rules! __rust_force_expr {
|
||||
($e:expr) => {
|
||||
$e
|
||||
};
|
||||
{
|
||||
let mut v = Vec::new();
|
||||
v.push(1u32);
|
||||
v.push(2);
|
||||
v
|
||||
}
|
||||
|
||||
fn main() {
|
||||
__rust_force_expr!(crate:: vec:: Vec:: new());
|
||||
__rust_force_expr!(<[_]>:: into_vec(#[rustc_box] crate:: boxed:: Box:: new([1u32, 2])));
|
||||
__rust_force_expr/*+errors*/!(crate:: vec:: from_elem((a.), $n));
|
||||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
macro_rules! __rust_force_expr {
|
||||
($e:expr) => {
|
||||
$e
|
||||
};
|
||||
}
|
||||
|
||||
fn main() {
|
||||
(crate ::vec::Vec::new());
|
||||
(<[_]>::into_vec(#[rustc_box] crate ::boxed::Box::new([1u32, 2])));
|
||||
/* error: expected Expr *//* parse error: expected field name or number */
|
||||
/* parse error: expected expression */
|
||||
/* parse error: expected R_PAREN */
|
||||
/* parse error: expected COMMA */
|
||||
/* parse error: expected expression, item or let statement */
|
||||
(crate ::vec::from_elem((a.), $n));
|
||||
}
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
|
|
@ -589,6 +589,16 @@ impl Resolver {
|
|||
})
|
||||
}
|
||||
|
||||
pub fn type_owner(&self) -> Option<TypeOwnerId> {
|
||||
self.scopes().find_map(|scope| match scope {
|
||||
Scope::BlockScope(_) => None,
|
||||
&Scope::GenericParams { def, .. } => Some(def.into()),
|
||||
&Scope::ImplDefScope(id) => Some(id.into()),
|
||||
&Scope::AdtScope(adt) => Some(adt.into()),
|
||||
Scope::ExprScope(it) => Some(it.owner.into()),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn impl_def(&self) -> Option<ImplId> {
|
||||
self.scopes().find_map(|scope| match scope {
|
||||
Scope::ImplDefScope(def) => Some(*def),
|
||||
|
@ -1079,7 +1089,6 @@ impl HasResolver for TypeOwnerId {
|
|||
TypeOwnerId::TypeAliasId(it) => it.resolver(db),
|
||||
TypeOwnerId::ImplId(it) => it.resolver(db),
|
||||
TypeOwnerId::EnumVariantId(it) => it.resolver(db),
|
||||
TypeOwnerId::ModuleId(it) => it.resolver(db),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue