mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-09-30 22:01:37 +00:00
Merge commit '9d8889cdfc
' into sync-from-ra
This commit is contained in:
parent
3afeb24198
commit
6bbd106c70
104 changed files with 1652 additions and 1026 deletions
|
@ -167,7 +167,7 @@ impl chalk_solve::RustIrDatabase<Interner> for ChalkContext<'_> {
|
|||
}
|
||||
});
|
||||
})
|
||||
.map(|block_id| self.db.trait_impls_in_block(block_id));
|
||||
.filter_map(|block_id| self.db.trait_impls_in_block(block_id));
|
||||
|
||||
let id_to_chalk = |id: hir_def::ImplId| id.to_chalk(self.db);
|
||||
let mut result = vec![];
|
||||
|
@ -183,7 +183,8 @@ impl chalk_solve::RustIrDatabase<Interner> for ChalkContext<'_> {
|
|||
def_blocks
|
||||
.into_iter()
|
||||
.flatten()
|
||||
.for_each(|it| f(&self.db.trait_impls_in_block(it)));
|
||||
.filter_map(|it| self.db.trait_impls_in_block(it))
|
||||
.for_each(|it| f(&it));
|
||||
}
|
||||
fps => {
|
||||
let mut f =
|
||||
|
@ -198,7 +199,8 @@ impl chalk_solve::RustIrDatabase<Interner> for ChalkContext<'_> {
|
|||
def_blocks
|
||||
.into_iter()
|
||||
.flatten()
|
||||
.for_each(|it| f(&self.db.trait_impls_in_block(it)));
|
||||
.filter_map(|it| self.db.trait_impls_in_block(it))
|
||||
.for_each(|it| f(&it));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -34,6 +34,8 @@ pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> {
|
|||
#[salsa::invoke(crate::infer::infer_query)]
|
||||
fn infer_query(&self, def: DefWithBodyId) -> Arc<InferenceResult>;
|
||||
|
||||
// region:mir
|
||||
|
||||
#[salsa::invoke(crate::mir::mir_body_query)]
|
||||
#[salsa::cycle(crate::mir::mir_body_recover)]
|
||||
fn mir_body(&self, def: DefWithBodyId) -> Result<Arc<MirBody>, MirLowerError>;
|
||||
|
@ -61,20 +63,6 @@ pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> {
|
|||
#[salsa::invoke(crate::mir::borrowck_query)]
|
||||
fn borrowck(&self, def: DefWithBodyId) -> Result<Arc<[BorrowckResult]>, MirLowerError>;
|
||||
|
||||
#[salsa::invoke(crate::lower::ty_query)]
|
||||
#[salsa::cycle(crate::lower::ty_recover)]
|
||||
fn ty(&self, def: TyDefId) -> Binders<Ty>;
|
||||
|
||||
#[salsa::invoke(crate::lower::value_ty_query)]
|
||||
fn value_ty(&self, def: ValueTyDefId) -> Binders<Ty>;
|
||||
|
||||
#[salsa::invoke(crate::lower::impl_self_ty_query)]
|
||||
#[salsa::cycle(crate::lower::impl_self_ty_recover)]
|
||||
fn impl_self_ty(&self, def: ImplId) -> Binders<Ty>;
|
||||
|
||||
#[salsa::invoke(crate::lower::const_param_ty_query)]
|
||||
fn const_param_ty(&self, def: ConstParamId) -> Ty;
|
||||
|
||||
#[salsa::invoke(crate::consteval::const_eval_query)]
|
||||
#[salsa::cycle(crate::consteval::const_eval_recover)]
|
||||
fn const_eval(
|
||||
|
@ -92,6 +80,22 @@ pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> {
|
|||
#[salsa::cycle(crate::consteval::const_eval_discriminant_recover)]
|
||||
fn const_eval_discriminant(&self, def: EnumVariantId) -> Result<i128, ConstEvalError>;
|
||||
|
||||
// endregion:mir
|
||||
|
||||
#[salsa::invoke(crate::lower::ty_query)]
|
||||
#[salsa::cycle(crate::lower::ty_recover)]
|
||||
fn ty(&self, def: TyDefId) -> Binders<Ty>;
|
||||
|
||||
#[salsa::invoke(crate::lower::value_ty_query)]
|
||||
fn value_ty(&self, def: ValueTyDefId) -> Binders<Ty>;
|
||||
|
||||
#[salsa::invoke(crate::lower::impl_self_ty_query)]
|
||||
#[salsa::cycle(crate::lower::impl_self_ty_recover)]
|
||||
fn impl_self_ty(&self, def: ImplId) -> Binders<Ty>;
|
||||
|
||||
#[salsa::invoke(crate::lower::const_param_ty_query)]
|
||||
fn const_param_ty(&self, def: ConstParamId) -> Ty;
|
||||
|
||||
#[salsa::invoke(crate::lower::impl_trait_query)]
|
||||
fn impl_trait(&self, def: ImplId) -> Option<Binders<TraitRef>>;
|
||||
|
||||
|
@ -158,7 +162,7 @@ pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> {
|
|||
fn inherent_impls_in_crate(&self, krate: CrateId) -> Arc<InherentImpls>;
|
||||
|
||||
#[salsa::invoke(InherentImpls::inherent_impls_in_block_query)]
|
||||
fn inherent_impls_in_block(&self, block: BlockId) -> Arc<InherentImpls>;
|
||||
fn inherent_impls_in_block(&self, block: BlockId) -> Option<Arc<InherentImpls>>;
|
||||
|
||||
/// Collects all crates in the dependency graph that have impls for the
|
||||
/// given fingerprint. This is only used for primitive types and types
|
||||
|
@ -175,7 +179,7 @@ pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> {
|
|||
fn trait_impls_in_crate(&self, krate: CrateId) -> Arc<TraitImpls>;
|
||||
|
||||
#[salsa::invoke(TraitImpls::trait_impls_in_block_query)]
|
||||
fn trait_impls_in_block(&self, block: BlockId) -> Arc<TraitImpls>;
|
||||
fn trait_impls_in_block(&self, block: BlockId) -> Option<Arc<TraitImpls>>;
|
||||
|
||||
#[salsa::invoke(TraitImpls::trait_impls_in_deps_query)]
|
||||
fn trait_impls_in_deps(&self, krate: CrateId) -> Arc<[Arc<TraitImpls>]>;
|
||||
|
|
|
@ -1629,7 +1629,7 @@ pub fn write_visibility(
|
|||
) -> Result<(), HirDisplayError> {
|
||||
match vis {
|
||||
Visibility::Public => write!(f, "pub "),
|
||||
Visibility::Module(vis_id) => {
|
||||
Visibility::Module(vis_id, _) => {
|
||||
let def_map = module_id.def_map(f.db.upcast());
|
||||
let root_module_id = def_map.module_id(DefMap::ROOT);
|
||||
if vis_id == module_id {
|
||||
|
|
|
@ -12,10 +12,9 @@ use hir_def::{
|
|||
LocalEnumVariantId, LocalFieldId, StructId,
|
||||
};
|
||||
use la_arena::{Idx, RawIdx};
|
||||
use rustc_dependencies::{
|
||||
abi::AddressSpace,
|
||||
index::{IndexSlice, IndexVec},
|
||||
};
|
||||
use rustc_abi::AddressSpace;
|
||||
use rustc_index::{IndexSlice, IndexVec};
|
||||
|
||||
use stdx::never;
|
||||
use triomphe::Arc;
|
||||
|
||||
|
@ -35,7 +34,7 @@ mod target;
|
|||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
pub struct RustcEnumVariantIdx(pub LocalEnumVariantId);
|
||||
|
||||
impl rustc_dependencies::index::Idx for RustcEnumVariantIdx {
|
||||
impl rustc_index::Idx for RustcEnumVariantIdx {
|
||||
fn new(idx: usize) -> Self {
|
||||
RustcEnumVariantIdx(Idx::from_raw(RawIdx::from(idx as u32)))
|
||||
}
|
||||
|
@ -54,7 +53,7 @@ impl RustcFieldIdx {
|
|||
}
|
||||
}
|
||||
|
||||
impl rustc_dependencies::index::Idx for RustcFieldIdx {
|
||||
impl rustc_index::Idx for RustcFieldIdx {
|
||||
fn new(idx: usize) -> Self {
|
||||
RustcFieldIdx(Idx::from_raw(RawIdx::from(idx as u32)))
|
||||
}
|
||||
|
|
|
@ -9,7 +9,7 @@ use hir_def::{
|
|||
AdtId, EnumVariantId, LocalEnumVariantId, VariantId,
|
||||
};
|
||||
use la_arena::RawIdx;
|
||||
use rustc_dependencies::index::IndexVec;
|
||||
use rustc_index::IndexVec;
|
||||
use smallvec::SmallVec;
|
||||
use triomphe::Arc;
|
||||
|
||||
|
|
|
@ -118,7 +118,7 @@ fn check_fail(ra_fixture: &str, e: LayoutError) {
|
|||
macro_rules! size_and_align {
|
||||
(minicore: $($x:tt),*;$($t:tt)*) => {
|
||||
{
|
||||
#[allow(dead_code)]
|
||||
#![allow(dead_code)]
|
||||
$($t)*
|
||||
check_size_and_align(
|
||||
stringify!($($t)*),
|
||||
|
@ -130,7 +130,7 @@ macro_rules! size_and_align {
|
|||
};
|
||||
($($t:tt)*) => {
|
||||
{
|
||||
#[allow(dead_code)]
|
||||
#![allow(dead_code)]
|
||||
$($t)*
|
||||
check_size_and_align(
|
||||
stringify!($($t)*),
|
||||
|
|
|
@ -3,10 +3,17 @@
|
|||
#![warn(rust_2018_idioms, unused_lifetimes)]
|
||||
#![cfg_attr(feature = "in-rust-tree", feature(rustc_private))]
|
||||
|
||||
#[allow(unused)]
|
||||
macro_rules! eprintln {
|
||||
($($tt:tt)*) => { stdx::eprintln!($($tt)*) };
|
||||
}
|
||||
#[cfg(feature = "in-rust-tree")]
|
||||
extern crate rustc_index;
|
||||
|
||||
#[cfg(not(feature = "in-rust-tree"))]
|
||||
extern crate ra_ap_rustc_index as rustc_index;
|
||||
|
||||
#[cfg(feature = "in-rust-tree")]
|
||||
extern crate rustc_abi;
|
||||
|
||||
#[cfg(not(feature = "in-rust-tree"))]
|
||||
extern crate ra_ap_rustc_abi as rustc_abi;
|
||||
|
||||
mod builder;
|
||||
mod chalk_db;
|
||||
|
|
|
@ -1601,7 +1601,7 @@ fn implicitly_sized_clauses<'a>(
|
|||
pub(crate) fn generic_defaults_query(
|
||||
db: &dyn HirDatabase,
|
||||
def: GenericDefId,
|
||||
) -> Arc<[Binders<chalk_ir::GenericArg<Interner>>]> {
|
||||
) -> Arc<[Binders<crate::GenericArg>]> {
|
||||
let resolver = def.resolver(db.upcast());
|
||||
let ctx = TyLoweringContext::new(db, &resolver, def.into())
|
||||
.with_type_param_mode(ParamLoweringMode::Variable);
|
||||
|
|
|
@ -8,10 +8,9 @@ use base_db::{CrateId, Edition};
|
|||
use chalk_ir::{cast::Cast, Mutability, TyKind, UniverseIndex, WhereClause};
|
||||
use hir_def::{
|
||||
data::{adt::StructFlags, ImplData},
|
||||
item_scope::ItemScope,
|
||||
nameres::DefMap,
|
||||
AssocItemId, BlockId, ConstId, FunctionId, HasModule, ImplId, ItemContainerId, Lookup,
|
||||
ModuleDefId, ModuleId, TraitId,
|
||||
ModuleId, TraitId,
|
||||
};
|
||||
use hir_expand::name::Name;
|
||||
use rustc_hash::{FxHashMap, FxHashSet};
|
||||
|
@ -132,34 +131,40 @@ pub(crate) const ALL_FLOAT_FPS: [TyFingerprint; 2] = [
|
|||
TyFingerprint::Scalar(Scalar::Float(FloatTy::F64)),
|
||||
];
|
||||
|
||||
type TraitFpMap = FxHashMap<TraitId, FxHashMap<Option<TyFingerprint>, Box<[ImplId]>>>;
|
||||
type TraitFpMapCollector = FxHashMap<TraitId, FxHashMap<Option<TyFingerprint>, Vec<ImplId>>>;
|
||||
|
||||
/// Trait impls defined or available in some crate.
|
||||
#[derive(Debug, Eq, PartialEq)]
|
||||
pub struct TraitImpls {
|
||||
// If the `Option<TyFingerprint>` is `None`, the impl may apply to any self type.
|
||||
map: FxHashMap<TraitId, FxHashMap<Option<TyFingerprint>, Vec<ImplId>>>,
|
||||
map: TraitFpMap,
|
||||
}
|
||||
|
||||
impl TraitImpls {
|
||||
pub(crate) fn trait_impls_in_crate_query(db: &dyn HirDatabase, krate: CrateId) -> Arc<Self> {
|
||||
let _p = profile::span("trait_impls_in_crate_query").detail(|| format!("{krate:?}"));
|
||||
let mut impls = Self { map: FxHashMap::default() };
|
||||
let mut impls = FxHashMap::default();
|
||||
|
||||
let crate_def_map = db.crate_def_map(krate);
|
||||
impls.collect_def_map(db, &crate_def_map);
|
||||
impls.shrink_to_fit();
|
||||
Self::collect_def_map(db, &mut impls, &db.crate_def_map(krate));
|
||||
|
||||
Arc::new(impls)
|
||||
Arc::new(Self::finish(impls))
|
||||
}
|
||||
|
||||
pub(crate) fn trait_impls_in_block_query(db: &dyn HirDatabase, block: BlockId) -> Arc<Self> {
|
||||
pub(crate) fn trait_impls_in_block_query(
|
||||
db: &dyn HirDatabase,
|
||||
block: BlockId,
|
||||
) -> Option<Arc<Self>> {
|
||||
let _p = profile::span("trait_impls_in_block_query");
|
||||
let mut impls = Self { map: FxHashMap::default() };
|
||||
let mut impls = FxHashMap::default();
|
||||
|
||||
let block_def_map = db.block_def_map(block);
|
||||
impls.collect_def_map(db, &block_def_map);
|
||||
impls.shrink_to_fit();
|
||||
Self::collect_def_map(db, &mut impls, &db.block_def_map(block));
|
||||
|
||||
Arc::new(impls)
|
||||
if impls.is_empty() {
|
||||
None
|
||||
} else {
|
||||
Some(Arc::new(Self::finish(impls)))
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn trait_impls_in_deps_query(
|
||||
|
@ -174,15 +179,16 @@ impl TraitImpls {
|
|||
)
|
||||
}
|
||||
|
||||
fn shrink_to_fit(&mut self) {
|
||||
self.map.shrink_to_fit();
|
||||
self.map.values_mut().for_each(|map| {
|
||||
map.shrink_to_fit();
|
||||
map.values_mut().for_each(Vec::shrink_to_fit);
|
||||
});
|
||||
fn finish(map: TraitFpMapCollector) -> TraitImpls {
|
||||
TraitImpls {
|
||||
map: map
|
||||
.into_iter()
|
||||
.map(|(k, v)| (k, v.into_iter().map(|(k, v)| (k, v.into_boxed_slice())).collect()))
|
||||
.collect(),
|
||||
}
|
||||
}
|
||||
|
||||
fn collect_def_map(&mut self, db: &dyn HirDatabase, def_map: &DefMap) {
|
||||
fn collect_def_map(db: &dyn HirDatabase, map: &mut TraitFpMapCollector, def_map: &DefMap) {
|
||||
for (_module_id, module_data) in def_map.modules() {
|
||||
for impl_id in module_data.scope.impls() {
|
||||
// Reservation impls should be ignored during trait resolution, so we never need
|
||||
|
@ -200,20 +206,15 @@ impl TraitImpls {
|
|||
};
|
||||
let self_ty = db.impl_self_ty(impl_id);
|
||||
let self_ty_fp = TyFingerprint::for_trait_impl(self_ty.skip_binders());
|
||||
self.map
|
||||
.entry(target_trait)
|
||||
.or_default()
|
||||
.entry(self_ty_fp)
|
||||
.or_default()
|
||||
.push(impl_id);
|
||||
map.entry(target_trait).or_default().entry(self_ty_fp).or_default().push(impl_id);
|
||||
}
|
||||
|
||||
// To better support custom derives, collect impls in all unnamed const items.
|
||||
// const _: () = { ... };
|
||||
for konst in collect_unnamed_consts(db, &module_data.scope) {
|
||||
for konst in module_data.scope.unnamed_consts(db.upcast()) {
|
||||
let body = db.body(konst.into());
|
||||
for (_, block_def_map) in body.blocks(db.upcast()) {
|
||||
self.collect_def_map(db, &block_def_map);
|
||||
Self::collect_def_map(db, map, &block_def_map);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -281,7 +282,10 @@ impl InherentImpls {
|
|||
Arc::new(impls)
|
||||
}
|
||||
|
||||
pub(crate) fn inherent_impls_in_block_query(db: &dyn HirDatabase, block: BlockId) -> Arc<Self> {
|
||||
pub(crate) fn inherent_impls_in_block_query(
|
||||
db: &dyn HirDatabase,
|
||||
block: BlockId,
|
||||
) -> Option<Arc<Self>> {
|
||||
let _p = profile::span("inherent_impls_in_block_query");
|
||||
let mut impls = Self { map: FxHashMap::default(), invalid_impls: Vec::default() };
|
||||
|
||||
|
@ -289,7 +293,11 @@ impl InherentImpls {
|
|||
impls.collect_def_map(db, &block_def_map);
|
||||
impls.shrink_to_fit();
|
||||
|
||||
Arc::new(impls)
|
||||
if impls.map.is_empty() && impls.invalid_impls.is_empty() {
|
||||
None
|
||||
} else {
|
||||
Some(Arc::new(impls))
|
||||
}
|
||||
}
|
||||
|
||||
fn shrink_to_fit(&mut self) {
|
||||
|
@ -321,7 +329,7 @@ impl InherentImpls {
|
|||
|
||||
// To better support custom derives, collect impls in all unnamed const items.
|
||||
// const _: () = { ... };
|
||||
for konst in collect_unnamed_consts(db, &module_data.scope) {
|
||||
for konst in module_data.scope.unnamed_consts(db.upcast()) {
|
||||
let body = db.body(konst.into());
|
||||
for (_, block_def_map) in body.blocks(db.upcast()) {
|
||||
self.collect_def_map(db, &block_def_map);
|
||||
|
@ -367,34 +375,6 @@ pub(crate) fn incoherent_inherent_impl_crates(
|
|||
res
|
||||
}
|
||||
|
||||
fn collect_unnamed_consts<'a>(
|
||||
db: &'a dyn HirDatabase,
|
||||
scope: &'a ItemScope,
|
||||
) -> impl Iterator<Item = ConstId> + 'a {
|
||||
let unnamed_consts = scope.unnamed_consts();
|
||||
|
||||
// FIXME: Also treat consts named `_DERIVE_*` as unnamed, since synstructure generates those.
|
||||
// Should be removed once synstructure stops doing that.
|
||||
let synstructure_hack_consts = scope.values().filter_map(|(item, _)| match item {
|
||||
ModuleDefId::ConstId(id) => {
|
||||
let loc = id.lookup(db.upcast());
|
||||
let item_tree = loc.id.item_tree(db.upcast());
|
||||
if item_tree[loc.id.value]
|
||||
.name
|
||||
.as_ref()
|
||||
.map_or(false, |n| n.to_smol_str().starts_with("_DERIVE_"))
|
||||
{
|
||||
Some(id)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
_ => None,
|
||||
});
|
||||
|
||||
unnamed_consts.chain(synstructure_hack_consts)
|
||||
}
|
||||
|
||||
pub fn def_crates(
|
||||
db: &dyn HirDatabase,
|
||||
ty: &Ty,
|
||||
|
@ -737,7 +717,7 @@ fn lookup_impl_assoc_item_for_trait_ref(
|
|||
let impls = db.trait_impls_in_deps(env.krate);
|
||||
let self_impls = match self_ty.kind(Interner) {
|
||||
TyKind::Adt(id, _) => {
|
||||
id.0.module(db.upcast()).containing_block().map(|it| db.trait_impls_in_block(it))
|
||||
id.0.module(db.upcast()).containing_block().and_then(|it| db.trait_impls_in_block(it))
|
||||
}
|
||||
_ => None,
|
||||
};
|
||||
|
@ -1254,17 +1234,18 @@ fn iterate_inherent_methods(
|
|||
};
|
||||
|
||||
while let Some(block_id) = block {
|
||||
let impls = db.inherent_impls_in_block(block_id);
|
||||
impls_for_self_ty(
|
||||
&impls,
|
||||
self_ty,
|
||||
table,
|
||||
name,
|
||||
receiver_ty,
|
||||
receiver_adjustments.clone(),
|
||||
module,
|
||||
callback,
|
||||
)?;
|
||||
if let Some(impls) = db.inherent_impls_in_block(block_id) {
|
||||
impls_for_self_ty(
|
||||
&impls,
|
||||
self_ty,
|
||||
table,
|
||||
name,
|
||||
receiver_ty,
|
||||
receiver_adjustments.clone(),
|
||||
module,
|
||||
callback,
|
||||
)?;
|
||||
}
|
||||
|
||||
block = db.block_def_map(block_id).parent().and_then(|module| module.containing_block());
|
||||
}
|
||||
|
|
|
@ -9,7 +9,6 @@ use base_db::{
|
|||
use hir_def::{db::DefDatabase, ModuleId};
|
||||
use hir_expand::db::ExpandDatabase;
|
||||
use nohash_hasher::IntMap;
|
||||
use rustc_hash::FxHashSet;
|
||||
use syntax::TextRange;
|
||||
use test_utils::extract_annotations;
|
||||
use triomphe::Arc;
|
||||
|
@ -81,7 +80,7 @@ impl FileLoader for TestDB {
|
|||
fn resolve_path(&self, path: AnchoredPath<'_>) -> Option<FileId> {
|
||||
FileLoaderDelegate(self).resolve_path(path)
|
||||
}
|
||||
fn relevant_crates(&self, file_id: FileId) -> Arc<FxHashSet<CrateId>> {
|
||||
fn relevant_crates(&self, file_id: FileId) -> Arc<[CrateId]> {
|
||||
FileLoaderDelegate(self).relevant_crates(file_id)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -987,15 +987,12 @@ fn infer_builtin_macros_env() {
|
|||
fn infer_builtin_macros_option_env() {
|
||||
check_types(
|
||||
r#"
|
||||
//- minicore: option
|
||||
//- /main.rs env:foo=bar
|
||||
#[rustc_builtin_macro]
|
||||
macro_rules! option_env {() => {}}
|
||||
|
||||
fn main() {
|
||||
let x = option_env!("foo");
|
||||
//^ Option<&str>
|
||||
}
|
||||
//- minicore: env
|
||||
//- /main.rs env:foo=bar
|
||||
fn main() {
|
||||
let x = option_env!("foo");
|
||||
//^ Option<&str>
|
||||
}
|
||||
"#,
|
||||
);
|
||||
}
|
||||
|
@ -1014,6 +1011,21 @@ fn test() {
|
|||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn infer_builtin_derive_resolves_with_core_module() {
|
||||
check_types(
|
||||
r#"
|
||||
//- minicore: derive, clone
|
||||
mod core {}
|
||||
#[derive(Clone)]
|
||||
struct S;
|
||||
fn test() {
|
||||
S.clone();
|
||||
} //^^^^^^^^^ S
|
||||
"#,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn infer_derive_clone_with_params() {
|
||||
check_types(
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue