diff --git a/compiler/rustc_data_structures/src/sharded.rs b/compiler/rustc_data_structures/src/sharded.rs index e10ccccad5bb4..3c90fcba3b540 100644 --- a/compiler/rustc_data_structures/src/sharded.rs +++ b/compiler/rustc_data_structures/src/sharded.rs @@ -199,6 +199,16 @@ impl ShardedHashMap { } } } + + #[inline] + pub fn remove(&self, key: &K) { + let hash = make_hash(key); + let mut shard = self.lock_shard_by_hash(hash); + + if let Entry::Occupied(e) = table_entry(&mut shard, hash, key) { + e.remove(); + } + } } impl ShardedHashMap { diff --git a/compiler/rustc_data_structures/src/vec_cache.rs b/compiler/rustc_data_structures/src/vec_cache.rs index 6d026bb2c7f74..78eb27f139856 100644 --- a/compiler/rustc_data_structures/src/vec_cache.rs +++ b/compiler/rustc_data_structures/src/vec_cache.rs @@ -206,6 +206,24 @@ impl SlotIndex { index_and_lock.store(extra.checked_add(2).unwrap(), Ordering::Release); } + + #[inline] + unsafe fn remove(&self, buckets: &[AtomicPtr>; 21]) { + let bucket = &buckets[self.bucket_idx]; + let ptr = self.bucket_ptr(bucket); + + debug_assert!(self.index_in_bucket < self.bucket_idx.capacity()); + + // SAFETY: `bucket` was allocated (so <= isize in total bytes) to hold `entries`, so this + // must be inbounds. + let slot = unsafe { ptr.add(self.index_in_bucket) }; + + // SAFETY: initialized bucket has zeroed all memory within the bucket, so we are valid for + // AtomicU32 access. + let index_and_lock = unsafe { &(*slot).index_and_lock }; + + index_and_lock.store(0, Ordering::Release); + } } /// In-memory cache for queries whose keys are densely-numbered IDs @@ -339,6 +357,39 @@ where pub fn len(&self) -> usize { self.len.load(Ordering::Acquire) } + + pub fn remove(&self, key: &K) { + let key = u32::try_from(key.index()).unwrap(); + let slot_idx = SlotIndex::from_index(key); + + unsafe { slot_idx.remove(&self.buckets) }; + } + + pub fn invalidate(&self, selector: impl Fn(K) -> bool) { + let mut to_remove = vec![]; + let mut remaining = vec![]; + + self.for_each(&mut |key, _, _| { + if selector(*key) { + to_remove.push(*key); + } else { + remaining.push(*key); + } + }); + + for key in to_remove { + self.remove(&key); + } + + for (index, key) in remaining.iter().enumerate() { + let slot = SlotIndex::from_index(u32::try_from(index).unwrap()); + let key = u32::try_from(key.index()).unwrap(); + + unsafe { slot.put_unique(&self.present, (), key) }; + } + + self.len.store(remaining.len(), Ordering::Release); + } } /// Index into an array of buckets. diff --git a/compiler/rustc_hir/src/definitions.rs b/compiler/rustc_hir/src/definitions.rs index 5e361891f6d04..cbac1c3c8209b 100644 --- a/compiler/rustc_hir/src/definitions.rs +++ b/compiler/rustc_hir/src/definitions.rs @@ -7,6 +7,7 @@ use std::fmt::{self, Write}; use std::hash::Hash; +use rustc_data_structures::indexmap::IndexSet; use rustc_data_structures::stable_hasher::StableHasher; use rustc_data_structures::unord::UnordMap; use rustc_hashes::Hash64; @@ -30,6 +31,7 @@ pub struct DefPathTable { // We do only store the local hash, as all the definitions are from the current crate. def_path_hashes: IndexVec, def_path_hash_to_index: DefPathHashMap, + allow_overwrite: IndexSet, } impl DefPathTable { @@ -39,38 +41,45 @@ impl DefPathTable { index_to_key: Default::default(), def_path_hashes: Default::default(), def_path_hash_to_index: Default::default(), + allow_overwrite: Default::default(), } } - fn allocate(&mut self, key: DefKey, def_path_hash: DefPathHash) -> DefIndex { + fn allocate(&mut self, key: DefKey, def_path_hash: DefPathHash, in_sandbox: bool) -> DefIndex { // Assert that all DefPathHashes correctly contain the local crate's StableCrateId. debug_assert_eq!(self.stable_crate_id, def_path_hash.stable_crate_id()); let local_hash = def_path_hash.local_hash(); - - let index = self.index_to_key.push(key); - debug!("DefPathTable::insert() - {key:?} <-> {index:?}"); - - self.def_path_hashes.push(local_hash); - debug_assert!(self.def_path_hashes.len() == self.index_to_key.len()); + let index = self.index_to_key.next_index(); // Check for hash collisions of DefPathHashes. These should be // exceedingly rare. if let Some(existing) = self.def_path_hash_to_index.insert(&local_hash, &index) { - let def_path1 = DefPath::make(LOCAL_CRATE, existing, |idx| self.def_key(idx)); - let def_path2 = DefPath::make(LOCAL_CRATE, index, |idx| self.def_key(idx)); - - // Continuing with colliding DefPathHashes can lead to correctness - // issues. We must abort compilation. - // - // The likelihood of such a collision is very small, so actually - // running into one could be indicative of a poor hash function - // being used. - // - // See the documentation for DefPathHash for more information. - panic!( - "found DefPathHash collision between {def_path1:#?} and {def_path2:#?}. \ + if !in_sandbox && self.allow_overwrite.swap_remove(&existing) { + self.def_path_hash_to_index.insert(&local_hash, &existing); + return existing; + } else { + let def_path1 = DefPath::make(LOCAL_CRATE, existing, |idx| self.def_key(idx)); + let def_path2 = DefPath::make(LOCAL_CRATE, index, |idx| self.def_key(idx)); + + // Continuing with colliding DefPathHashes can lead to correctness + // issues. We must abort compilation. + // + // The likelihood of such a collision is very small, so actually + // running into one could be indicative of a poor hash function + // being used. + // + // See the documentation for DefPathHash for more information. + panic!( + "found DefPathHash collision between {def_path1:#?} and {def_path2:#?}. \ Compilation cannot continue." - ); + ); + } + } else { + self.index_to_key.push(key); + debug!("DefPathTable::insert() - {key:?} <-> {index:?}"); + + self.def_path_hashes.push(local_hash); + debug_assert!(self.def_path_hashes.len() == self.index_to_key.len()); } index @@ -374,7 +383,7 @@ impl Definitions { // Create the root definition. let mut table = DefPathTable::new(stable_crate_id); - let root = LocalDefId { local_def_index: table.allocate(key, def_path_hash) }; + let root = LocalDefId { local_def_index: table.allocate(key, def_path_hash, false) }; assert_eq!(root.local_def_index, CRATE_DEF_INDEX); Definitions { table } @@ -390,6 +399,7 @@ impl Definitions { parent: LocalDefId, data: DefPathData, disambiguator: &mut DisambiguatorState, + in_sandbox: bool, ) -> LocalDefId { // We can't use `Debug` implementation for `LocalDefId` here, since it tries to acquire a // reference to `Definitions` and we're already holding a mutable reference. @@ -418,8 +428,14 @@ impl Definitions { debug!("create_def: after disambiguation, key = {:?}", key); + let local_def_index = self.table.allocate(key, def_path_hash, in_sandbox); + + if in_sandbox { + assert_eq!(self.table.allow_overwrite.insert(local_def_index), true); + } + // Create the definition. - LocalDefId { local_def_index: self.table.allocate(key, def_path_hash) } + LocalDefId { local_def_index } } #[inline(always)] diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs index 99511189e9283..9ffcd3461f2de 100644 --- a/compiler/rustc_hir/src/intravisit.rs +++ b/compiler/rustc_hir/src/intravisit.rs @@ -226,6 +226,11 @@ pub trait Visitor<'v>: Sized { /// or `ControlFlow`. type Result: VisitorResult = (); + #[inline] + fn visit_if_delayed(&self, _: LocalDefId) -> bool { + true + } + /// If `type NestedFilter` is set to visit nested items, this method /// must also be overridden to provide a map to retrieve nested items. fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt { @@ -244,18 +249,23 @@ pub trait Visitor<'v>: Sized { /// this method is if you want a nested pattern but cannot supply a /// `TyCtxt`; see `maybe_tcx` for advice. fn visit_nested_item(&mut self, id: ItemId) -> Self::Result { - if Self::NestedFilter::INTER { + if self.should_visit_maybe_delayed_inter(id.owner_id.def_id) { let item = self.maybe_tcx().hir_item(id); try_visit!(self.visit_item(item)); } Self::Result::output() } + // Now delayed owners are only delegations, which are either item, trait item or impl item. + fn should_visit_maybe_delayed_inter(&mut self, id: LocalDefId) -> bool { + Self::NestedFilter::INTER && self.visit_if_delayed(id) + } + /// Like `visit_nested_item()`, but for trait items. See /// `visit_nested_item()` for advice on when to override this /// method. fn visit_nested_trait_item(&mut self, id: TraitItemId) -> Self::Result { - if Self::NestedFilter::INTER { + if self.should_visit_maybe_delayed_inter(id.owner_id.def_id) { let item = self.maybe_tcx().hir_trait_item(id); try_visit!(self.visit_trait_item(item)); } @@ -266,7 +276,7 @@ pub trait Visitor<'v>: Sized { /// `visit_nested_item()` for advice on when to override this /// method. fn visit_nested_impl_item(&mut self, id: ImplItemId) -> Self::Result { - if Self::NestedFilter::INTER { + if self.should_visit_maybe_delayed_inter(id.owner_id.def_id) { let item = self.maybe_tcx().hir_impl_item(id); try_visit!(self.visit_impl_item(item)); } diff --git a/compiler/rustc_macros/src/query.rs b/compiler/rustc_macros/src/query.rs index 3880894572c93..7b191b170be40 100644 --- a/compiler/rustc_macros/src/query.rs +++ b/compiler/rustc_macros/src/query.rs @@ -138,6 +138,7 @@ struct QueryModifiers { // tidy-alphabetical-start arena_cache: Option, cache_on_disk: Option, + callfront: Option, depth_limit: Option, desc: Desc, eval_always: Option, @@ -153,6 +154,7 @@ fn parse_query_modifiers(input: ParseStream<'_>) -> Result { // tidy-alphabetical-start let mut arena_cache = None; let mut cache_on_disk = None; + let mut callfront = None; let mut depth_limit = None; let mut desc = None; let mut eval_always = None; @@ -179,6 +181,8 @@ fn parse_query_modifiers(input: ParseStream<'_>) -> Result { try_insert!(arena_cache = modifier); } else if modifier == "cache_on_disk" { try_insert!(cache_on_disk = modifier); + } else if modifier == "callfront" { + try_insert!(callfront = modifier); } else if modifier == "depth_limit" { try_insert!(depth_limit = modifier); } else if modifier == "desc" { @@ -211,6 +215,7 @@ fn parse_query_modifiers(input: ParseStream<'_>) -> Result { // tidy-alphabetical-start arena_cache, cache_on_disk, + callfront, depth_limit, desc, eval_always, @@ -247,6 +252,7 @@ fn make_modifiers_stream(query: &Query) -> proc_macro2::TokenStream { // tidy-alphabetical-start arena_cache, cache_on_disk, + callfront, depth_limit, desc, eval_always, @@ -261,6 +267,7 @@ fn make_modifiers_stream(query: &Query) -> proc_macro2::TokenStream { // tidy-alphabetical-start let arena_cache = arena_cache.is_some(); let cache_on_disk = cache_on_disk.is_some(); + let callfront = callfront.is_some(); let depth_limit = depth_limit.is_some(); let desc = { // Put a description closure in the `desc` modifier. @@ -284,7 +291,7 @@ fn make_modifiers_stream(query: &Query) -> proc_macro2::TokenStream { // tidy-alphabetical-end // Giving an input span to the modifier names in the modifier list seems - // to give slightly more helpful errors when one of the callback macros + // to give slightly more helpful errors when one of the callfront macros // fails to parse the modifier list. let query_name_span = query.name.span(); quote_spanned! { @@ -293,6 +300,7 @@ fn make_modifiers_stream(query: &Query) -> proc_macro2::TokenStream { // tidy-alphabetical-start arena_cache: #arena_cache, cache_on_disk: #cache_on_disk, + callfront: #callfront, depth_limit: #depth_limit, desc: #desc, eval_always: #eval_always, diff --git a/compiler/rustc_middle/src/dep_graph/graph.rs b/compiler/rustc_middle/src/dep_graph/graph.rs index be29e053a17c0..f2d074cd904bf 100644 --- a/compiler/rustc_middle/src/dep_graph/graph.rs +++ b/compiler/rustc_middle/src/dep_graph/graph.rs @@ -2,7 +2,7 @@ use std::assert_matches; use std::fmt::Debug; use std::hash::Hash; use std::sync::Arc; -use std::sync::atomic::{AtomicU32, Ordering}; +use std::sync::atomic::{AtomicBool, AtomicU32, Ordering}; use rustc_data_structures::fingerprint::{Fingerprint, PackedFingerprint}; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; @@ -55,7 +55,8 @@ pub enum QuerySideEffect { #[derive(Clone)] pub struct DepGraph { - data: Option>, + is_in_sandbox: Arc, + data: [Option>; 2], /// This field is used for assigning DepNodeIndices when running in /// non-incremental mode. Even in non-incremental mode we make sure that @@ -170,40 +171,47 @@ impl DepGraph { } DepGraph { - data: Some(Arc::new(DepGraphData { - previous_work_products: prev_work_products, - current, - previous: prev_graph, - colors, - debug_loaded_from_disk: Default::default(), - })), + data: [ + Some(Arc::new(DepGraphData { + previous_work_products: prev_work_products, + current, + previous: prev_graph, + colors, + debug_loaded_from_disk: Default::default(), + })), + None, + ], virtual_dep_node_index: Arc::new(AtomicU32::new(0)), + is_in_sandbox: Default::default(), } } pub fn new_disabled() -> DepGraph { - DepGraph { data: None, virtual_dep_node_index: Arc::new(AtomicU32::new(0)) } + DepGraph { + data: [None, None], + virtual_dep_node_index: Arc::new(AtomicU32::new(0)), + is_in_sandbox: Default::default(), + } } - #[inline] pub fn data(&self) -> Option<&DepGraphData> { - self.data.as_deref() + self.data[self.is_in_sandbox.load(Ordering::Relaxed) as usize].as_deref() } /// Returns `true` if we are actually building the full dep-graph, and `false` otherwise. #[inline] pub fn is_fully_enabled(&self) -> bool { - self.data.is_some() + self.data().is_some() } pub fn with_retained_dep_graph(&self, f: impl Fn(&RetainedDepGraph)) { - if let Some(data) = &self.data { + if let Some(data) = self.data() { data.current.encoder.with_retained_dep_graph(f) } } pub fn assert_ignored(&self) { - if let Some(..) = self.data { + if let Some(..) = self.data() { read_deps(|task_deps| { assert_matches!( task_deps, @@ -274,6 +282,16 @@ impl DepGraph { with_deps(TaskDepsRef::Forbid, op) } + pub fn with_sandbox(&self, op: impl FnOnce()) { + self.with_query_deserialization(|| { + self.is_in_sandbox.store(true, Ordering::Relaxed); + + op(); + + self.is_in_sandbox.store(false, Ordering::Relaxed); + }); + } + #[inline(always)] pub fn with_task<'tcx, OP, R>( &self, @@ -450,7 +468,7 @@ impl DepGraphData { impl DepGraph { #[inline] pub fn read_index(&self, dep_node_index: DepNodeIndex) { - if let Some(ref data) = self.data { + if let Some(ref data) = self.data() { read_deps(|task_deps| { let mut task_deps = match task_deps { TaskDepsRef::Allow(deps) => deps.lock(), @@ -507,7 +525,7 @@ impl DepGraph { /// it with the node, for use in the next session. #[inline] pub fn record_diagnostic<'tcx>(&self, tcx: TyCtxt<'tcx>, diagnostic: &DiagInner) { - if let Some(ref data) = self.data { + if let Some(ref data) = self.data() { read_deps(|task_deps| match task_deps { TaskDepsRef::EvalAlways | TaskDepsRef::Ignore => return, TaskDepsRef::Forbid | TaskDepsRef::Allow(..) => { @@ -522,7 +540,7 @@ impl DepGraph { /// refer to a node created used `encode_side_effect` in the previous session. #[inline] pub fn force_side_effect<'tcx>(&self, tcx: TyCtxt<'tcx>, prev_index: SerializedDepNodeIndex) { - if let Some(ref data) = self.data { + if let Some(ref data) = self.data() { data.force_side_effect(tcx, prev_index); } } @@ -533,7 +551,7 @@ impl DepGraph { tcx: TyCtxt<'tcx>, side_effect: QuerySideEffect, ) -> DepNodeIndex { - if let Some(ref data) = self.data { + if let Some(ref data) = self.data() { data.encode_side_effect(tcx, side_effect) } else { self.next_virtual_depnode_index() @@ -563,7 +581,7 @@ impl DepGraph { hash_result: Option, &R) -> Fingerprint>, format_value_fn: fn(&R) -> String, ) -> DepNodeIndex { - if let Some(data) = self.data.as_ref() { + if let Some(data) = self.data().as_ref() { // The caller query has more dependencies than the node we are creating. We may // encounter a case where this created node is marked as green, but the caller query is // subsequently marked as red or recomputed. In this case, we will end up feeding a @@ -808,23 +826,23 @@ impl DepGraph { /// Checks whether a previous work product exists for `v` and, if /// so, return the path that leads to it. Used to skip doing work. pub fn previous_work_product(&self, v: &WorkProductId) -> Option { - self.data.as_ref().and_then(|data| data.previous_work_products.get(v).cloned()) + self.data().as_ref().and_then(|data| data.previous_work_products.get(v).cloned()) } /// Access the map of work-products created during the cached run. Only /// used during saving of the dep-graph. pub fn previous_work_products(&self) -> &WorkProductMap { - &self.data.as_ref().unwrap().previous_work_products + &self.data().as_ref().unwrap().previous_work_products } pub fn debug_was_loaded_from_disk(&self, dep_node: DepNode) -> bool { - self.data.as_ref().unwrap().debug_loaded_from_disk.lock().contains(&dep_node) + self.data().as_ref().unwrap().debug_loaded_from_disk.lock().contains(&dep_node) } pub fn debug_dep_kind_was_loaded_from_disk(&self, dep_kind: DepKind) -> bool { // We only check if we have a dep node corresponding to the given dep kind. #[allow(rustc::potential_query_instability)] - self.data + self.data() .as_ref() .unwrap() .debug_loaded_from_disk @@ -834,7 +852,7 @@ impl DepGraph { } fn node_color(&self, dep_node: &DepNode) -> DepNodeColor { - if let Some(ref data) = self.data { + if let Some(ref data) = self.data() { return data.node_color(dep_node); } @@ -980,7 +998,7 @@ impl DepGraph { dep_node: &DepNode, msg: impl FnOnce() -> S, ) { - if let Some(data) = &self.data { + if let Some(data) = &self.data() { data.assert_dep_node_not_yet_allocated_in_current_session(sess, dep_node, msg) } } @@ -996,7 +1014,7 @@ impl DepGraph { pub fn exec_cache_promotions<'tcx>(&self, tcx: TyCtxt<'tcx>) { let _prof_timer = tcx.prof.generic_activity("incr_comp_query_cache_promotion"); - let data = self.data.as_ref().unwrap(); + let data = self.data().unwrap(); for prev_index in data.colors.values.indices() { match data.colors.get(prev_index) { DepNodeColor::Green(_) => { @@ -1017,11 +1035,15 @@ impl DepGraph { } pub(crate) fn finish_encoding(&self) -> FileEncodeResult { - if let Some(data) = &self.data { data.current.encoder.finish(&data.current) } else { Ok(0) } + if let Some(data) = &self.data() { + data.current.encoder.finish(&data.current) + } else { + Ok(0) + } } pub fn next_virtual_depnode_index(&self) -> DepNodeIndex { - debug_assert!(self.data.is_none()); + debug_assert!(self.data().is_none()); let index = self.virtual_dep_node_index.fetch_add(1, Ordering::Relaxed); DepNodeIndex::from_u32(index) } @@ -1396,7 +1418,7 @@ pub(super) enum TrySetColorResult { #[inline(never)] #[cold] pub(crate) fn print_markframe_trace(graph: &DepGraph, frame: &MarkFrame<'_>) { - let data = graph.data.as_ref().unwrap(); + let data = graph.data().unwrap(); eprintln!("there was a panic while trying to force a dep node"); eprintln!("try_mark_green dep node stack:"); diff --git a/compiler/rustc_middle/src/hir/map.rs b/compiler/rustc_middle/src/hir/map.rs index 20aa0a809006f..f12860235dd9e 100644 --- a/compiler/rustc_middle/src/hir/map.rs +++ b/compiler/rustc_middle/src/hir/map.rs @@ -7,7 +7,7 @@ use rustc_ast::visit::{VisitorResult, walk_list}; use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_data_structures::svh::Svh; -use rustc_data_structures::sync::{DynSend, DynSync, par_for_each_in, spawn, try_par_for_each_in}; +use rustc_data_structures::sync::{DynSend, DynSync, par_for_each_in, try_par_for_each_in}; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{DefId, LOCAL_CRATE, LocalDefId, LocalModDefId}; use rustc_hir::definitions::{DefKey, DefPath, DefPathHash}; @@ -1245,25 +1245,7 @@ pub(super) fn hir_module_items(tcx: TyCtxt<'_>, module_id: LocalModDefId) -> Mod } } -fn force_delayed_owners_lowering(tcx: TyCtxt<'_>) { - let krate = tcx.hir_crate(()); - for &id in &krate.delayed_ids { - tcx.ensure_done().lower_delayed_owner(id); - } - - let (_, krate) = krate.delayed_resolver.steal(); - let prof = tcx.sess.prof.clone(); - - // Drop AST to free memory. It can be expensive so try to drop it on a separate thread. - spawn(move || { - let _timer = prof.verbose_generic_activity("drop_ast"); - drop(krate); - }); -} - pub(crate) fn hir_crate_items(tcx: TyCtxt<'_>, _: ()) -> ModuleItems { - force_delayed_owners_lowering(tcx); - let mut collector = ItemCollector::new(tcx, true); // A "crate collector" and "module collector" start at a @@ -1352,6 +1334,10 @@ impl<'hir> Visitor<'hir> for ItemCollector<'hir> { self.tcx } + fn visit_if_delayed(&self, _: LocalDefId) -> bool { + !self.tcx.is_in_sandbox() + } + fn visit_item(&mut self, item: &'hir Item<'hir>) { if Node::Item(item).associated_body().is_some() { self.body_owners.push(item.owner_id.def_id); diff --git a/compiler/rustc_middle/src/hir/mod.rs b/compiler/rustc_middle/src/hir/mod.rs index 814b333cfb0f8..dc0c255dac9ab 100644 --- a/compiler/rustc_middle/src/hir/mod.rs +++ b/compiler/rustc_middle/src/hir/mod.rs @@ -14,7 +14,7 @@ use rustc_data_structures::fx::FxIndexSet; use rustc_data_structures::sorted_map::SortedMap; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_data_structures::steal::Steal; -use rustc_data_structures::sync::{DynSend, DynSync, try_par_for_each_in}; +use rustc_data_structures::sync::{DynSend, DynSync, spawn, try_par_for_each_in}; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{DefId, LocalDefId, LocalModDefId}; use rustc_hir::lints::DelayedLint; @@ -207,6 +207,30 @@ impl ModuleItems { } impl<'tcx> TyCtxt<'tcx> { + pub fn force_delayed_owners_lowering(self) { + let krate = self.hir_crate(()); + + if !krate.delayed_ids.is_empty() { + self.with_sandbox(|| { + self.ensure_done().hir_crate_items(()); + self.ensure_done().crate_inherent_impls(()); + + for &id in &krate.delayed_ids { + self.ensure_done().lower_delayed_owner(id); + } + }); + } + + let (_, krate) = krate.delayed_resolver.steal(); + let prof = self.sess.prof.clone(); + + // Drop AST to free memory. It can be expensive so try to drop it on a separate thread. + spawn(move || { + let _timer = prof.verbose_generic_activity("drop_ast"); + drop(krate); + }); + } + pub fn parent_module(self, id: HirId) -> LocalModDefId { if !id.is_owner() && self.def_kind(id.owner) == DefKind::Mod { LocalModDefId::new_unchecked(id.owner.def_id) diff --git a/compiler/rustc_middle/src/hooks/mod.rs b/compiler/rustc_middle/src/hooks/mod.rs index c70ceef1d47e9..9d3f75cd5a143 100644 --- a/compiler/rustc_middle/src/hooks/mod.rs +++ b/compiler/rustc_middle/src/hooks/mod.rs @@ -91,6 +91,9 @@ declare_hooks! { hook alloc_self_profile_query_strings() -> (); + hook enter_query_sandbox() -> (); + hook leave_query_sandbox() -> (); + /// Saves and writes the DepGraph to the file system. /// /// This function saves both the dep-graph and the query result cache, diff --git a/compiler/rustc_middle/src/infer/canonical.rs b/compiler/rustc_middle/src/infer/canonical.rs index 32c6b6e9c0ba1..02f86f62113f0 100644 --- a/compiler/rustc_middle/src/infer/canonical.rs +++ b/compiler/rustc_middle/src/infer/canonical.rs @@ -201,4 +201,8 @@ impl<'tcx> CanonicalParamEnvCache<'tcx> { } } } + + pub fn clear(&self) { + self.map.borrow_mut().clear(); + } } diff --git a/compiler/rustc_middle/src/lib.rs b/compiler/rustc_middle/src/lib.rs index 1d6132ba2a3ea..b479361d99bb2 100644 --- a/compiler/rustc_middle/src/lib.rs +++ b/compiler/rustc_middle/src/lib.rs @@ -42,6 +42,7 @@ #![feature(extern_types)] #![feature(file_buffered)] #![feature(gen_blocks)] +#![feature(lock_value_accessors)] #![feature(min_specialization)] #![feature(negative_impls)] #![feature(never_type)] diff --git a/compiler/rustc_middle/src/queries.rs b/compiler/rustc_middle/src/queries.rs index dd36cbf1b8f6f..cc8ef1def52cc 100644 --- a/compiler/rustc_middle/src/queries.rs +++ b/compiler/rustc_middle/src/queries.rs @@ -225,6 +225,7 @@ rustc_queries! { query hir_crate_items(_: ()) -> &'tcx rustc_middle::hir::ModuleItems { arena_cache eval_always + callfront desc { "getting HIR crate items" } } diff --git a/compiler/rustc_middle/src/query/caches.rs b/compiler/rustc_middle/src/query/caches.rs index 0c71a98b7fb29..63585973aa788 100644 --- a/compiler/rustc_middle/src/query/caches.rs +++ b/compiler/rustc_middle/src/query/caches.rs @@ -1,6 +1,5 @@ -use std::sync::OnceLock; - use rustc_data_structures::sharded::ShardedHashMap; +use rustc_data_structures::sync::Lock; pub use rustc_data_structures::vec_cache::VecCache; use rustc_hir::def_id::LOCAL_CRATE; use rustc_index::Idx; @@ -14,7 +13,7 @@ use crate::query::keys::QueryKey; /// /// Types implementing this trait are associated with actual key/value types /// by the `Cache` associated type of the `rustc_middle::query::Key` trait. -pub trait QueryCache: Sized { +pub trait QueryCache: Sized + Default { type Key: QueryKey; type Value: Copy; @@ -36,6 +35,8 @@ pub trait QueryCache: Sized { /// Useful for reserving capacity in data structures that will hold the /// output of a call to [`Self::for_each`]. fn len(&self) -> usize; + + fn invalidate(&self, selector: impl Fn(Self::Key) -> bool); } /// In-memory cache for queries whose keys aren't suitable for any of the @@ -81,17 +82,30 @@ where fn len(&self) -> usize { self.cache.len() } + + fn invalidate(&self, selector: impl Fn(Self::Key) -> bool) { + let mut to_remove = vec![]; + self.for_each(&mut |&key, _, _| { + if selector(key) { + to_remove.push(key); + } + }); + + for key in to_remove { + self.cache.remove(&key); + } + } } /// In-memory cache for queries whose key type only has one value (e.g. `()`). /// The cache therefore only needs to store one query return value. pub struct SingleCache { - cache: OnceLock<(V, DepNodeIndex)>, + cache: Lock>, } impl Default for SingleCache { fn default() -> Self { - SingleCache { cache: OnceLock::new() } + SingleCache { cache: Default::default() } } } @@ -104,22 +118,28 @@ where #[inline(always)] fn lookup(&self, _key: &()) -> Option<(V, DepNodeIndex)> { - self.cache.get().copied() + self.cache.lock().clone() } #[inline] fn complete(&self, _key: (), value: V, index: DepNodeIndex) { - self.cache.set((value, index)).ok(); + *self.cache.lock() = Some((value, index)) } fn for_each(&self, f: &mut dyn FnMut(&Self::Key, &Self::Value, DepNodeIndex)) { - if let Some(value) = self.cache.get() { + if let Some(value) = self.cache.lock().clone() { f(&(), &value.0, value.1) } } fn len(&self) -> usize { - self.cache.get().is_some().into() + self.cache.lock().is_some().into() + } + + fn invalidate(&self, selector: impl Fn(Self::Key) -> bool) { + if selector(()) { + *self.cache.lock() = None; + } } } @@ -175,6 +195,10 @@ where fn len(&self) -> usize { self.local.len() + self.foreign.len() } + + fn invalidate(&self, selector: impl Fn(Self::Key) -> bool) { + self.local.invalidate(|idx| selector(DefId::local(idx))); + } } impl QueryCache for VecCache @@ -202,4 +226,8 @@ where fn len(&self) -> usize { self.len() } + + fn invalidate(&self, selector: impl Fn(Self::Key) -> bool) { + self.invalidate(selector); + } } diff --git a/compiler/rustc_middle/src/query/inner.rs b/compiler/rustc_middle/src/query/inner.rs index 402c448a1fa3a..c18b995e4a5e8 100644 --- a/compiler/rustc_middle/src/query/inner.rs +++ b/compiler/rustc_middle/src/query/inner.rs @@ -22,6 +22,7 @@ where Some((value, index)) => { tcx.prof.query_cache_hit(index.into()); tcx.dep_graph.read_index(index); + Some(value) } None => None, @@ -165,6 +166,7 @@ pub(crate) fn query_feed<'tcx, C>( query.hash_value_fn, query.format_value, ); + query.cache.complete(key, value, dep_node_index); } } diff --git a/compiler/rustc_middle/src/query/modifiers.rs b/compiler/rustc_middle/src/query/modifiers.rs index 4fd91caa94cd7..fb646db244bb6 100644 --- a/compiler/rustc_middle/src/query/modifiers.rs +++ b/compiler/rustc_middle/src/query/modifiers.rs @@ -28,6 +28,9 @@ pub(crate) struct arena_cache; /// be loadable from crate metadata instead. pub(crate) struct cache_on_disk; +/// # `callfront` query modifier +pub(crate) struct callfront; + /// # `depth_limit` query modifier /// /// Impose a recursion call depth limit on the query to prevent stack overflow. diff --git a/compiler/rustc_middle/src/query/plumbing.rs b/compiler/rustc_middle/src/query/plumbing.rs index fe3054dc18e65..b6d3f23995685 100644 --- a/compiler/rustc_middle/src/query/plumbing.rs +++ b/compiler/rustc_middle/src/query/plumbing.rs @@ -1,8 +1,9 @@ use std::fmt; use std::ops::Deref; +use std::sync::Mutex; use rustc_data_structures::fingerprint::Fingerprint; -use rustc_data_structures::fx::FxIndexMap; +use rustc_data_structures::fx::{FxHashSet, FxIndexMap}; use rustc_data_structures::hash_table::HashTable; use rustc_data_structures::sharded::Sharded; use rustc_data_structures::sync::{AtomicU64, Lock, WorkerLocal}; @@ -24,11 +25,12 @@ use crate::ty::{self, TyCtxt}; /// query's in-memory cache.) pub struct QueryState<'tcx, K> { pub active: Sharded)>>, + pub saved_keys: Mutex>>, } impl<'tcx, K> Default for QueryState<'tcx, K> { fn default() -> QueryState<'tcx, K> { - QueryState { active: Default::default() } + QueryState { active: Default::default(), saved_keys: Default::default() } } } @@ -131,6 +133,26 @@ pub struct QueryVTable<'tcx, C: QueryCache> { /// /// [^1]: [`TyCtxt`], [`TyCtxtAt`], [`TyCtxtEnsureOk`], [`TyCtxtEnsureDone`] pub execute_query_fn: fn(TyCtxt<'tcx>, Span, C::Key, QueryMode) -> Option, + + pub callfront_fn: Option) -> ()>, +} + +impl QueryVTable<'_, C> { + pub fn save_keys(&self) { + let mut keys = FxHashSet::default(); + self.cache.for_each(&mut |key, _, _| { + keys.insert(*key); + }); + + self.state.saved_keys.set(Some(keys)).ok(); + } + + pub fn invalidate_saved_keys(&self) { + let keys = + self.state.saved_keys.replace(None).unwrap().expect("must save keys to invalidate"); + + self.cache.invalidate(|key| !keys.contains(&key)); + } } impl<'tcx, C: QueryCache> fmt::Debug for QueryVTable<'tcx, C> { @@ -301,6 +323,7 @@ macro_rules! define_callbacks { // Search for (QMODLIST) to find all occurrences of this query modifier list. arena_cache: $arena_cache:literal, cache_on_disk: $cache_on_disk:literal, + callfront: $callfront:literal, depth_limit: $depth_limit:literal, desc: $desc:expr, eval_always: $eval_always:literal, diff --git a/compiler/rustc_middle/src/traits/cache.rs b/compiler/rustc_middle/src/traits/cache.rs index 9391764bf1ce2..c4d00e73fe711 100644 --- a/compiler/rustc_middle/src/traits/cache.rs +++ b/compiler/rustc_middle/src/traits/cache.rs @@ -32,6 +32,10 @@ impl WithDepNodeCache { pub fn insert(&self, key: Key, dep_node: DepNodeIndex, value: Value) { self.hashmap.borrow_mut().insert(key, WithDepNode::new(dep_node, value)); } + + pub fn clear(&self) { + self.hashmap.borrow_mut().clear(); + } } #[derive(Debug, Clone, Eq, PartialEq)] diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index b908a6c6e8439..ff90236118a8d 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -12,6 +12,7 @@ use std::ffi::OsStr; use std::hash::{Hash, Hasher}; use std::marker::{PhantomData, PointeeSized}; use std::ops::{Bound, Deref}; +use std::sync::atomic::{AtomicBool, Ordering as AtomicOrdering}; use std::sync::{Arc, OnceLock}; use std::{fmt, iter, mem}; @@ -66,6 +67,7 @@ use crate::thir::Thir; use crate::traits; use crate::traits::solve::{ExternalConstraints, ExternalConstraintsData, PredefinedOpaques}; use crate::ty::predicate::ExistentialPredicateStableCmpExt as _; +use crate::ty::print::with_no_trimmed_paths; use crate::ty::{ self, AdtDef, AdtDefData, AdtKind, Binder, Clause, Clauses, Const, GenericArg, GenericArgs, GenericArgsRef, GenericParamDefKind, List, ListWithCachedTypeInfo, ParamConst, Pattern, @@ -797,6 +799,7 @@ pub struct GlobalCtxt<'tcx> { /// be called from rustc_middle. pub(crate) hooks: crate::hooks::Providers, + is_in_sandbox: AtomicBool, untracked: Untracked, pub query_system: QuerySystem<'tcx>, @@ -896,6 +899,33 @@ impl CurrentGcx { } impl<'tcx> TyCtxt<'tcx> { + pub fn is_in_sandbox(self) -> bool { + self.is_in_sandbox.load(AtomicOrdering::Relaxed) + } + + pub fn with_sandbox(self, op: impl FnOnce()) { + self.is_in_sandbox.store(true, AtomicOrdering::Relaxed); + self.enter_query_sandbox(); + + self.dep_graph.with_sandbox(|| { + with_no_trimmed_paths!({ + op(); + }); + }); + + self.leave_query_sandbox(); + self.is_in_sandbox.store(false, AtomicOrdering::Relaxed); + + self.clauses_cache.borrow_mut().clear(); + self.highest_var_in_clauses_cache.borrow_mut().clear(); + self.canonical_param_env_cache.clear(); + self.new_solver_canonical_param_env_cache.borrow_mut().clear(); + self.new_solver_evaluation_cache.borrow_mut().clear(); + self.evaluation_cache.clear(); + self.selection_cache.clear(); + self.ty_rcache.borrow_mut().clear(); + } + pub fn has_typeck_results(self, def_id: LocalDefId) -> bool { // Closures' typeck results come from their outermost function, // as they are part of the same "inference environment". @@ -1047,6 +1077,7 @@ impl<'tcx> TyCtxt<'tcx> { types: common_types, lifetimes: common_lifetimes, consts: common_consts, + is_in_sandbox: Default::default(), untracked, query_system, dep_kind_vtables, @@ -1385,7 +1416,12 @@ impl<'tcx> TyCtxt<'tcx> { // - has been created by this call to `create_def`. // As a consequence, this LocalDefId is always re-created before it is needed by the incr. // comp. engine itself. - let def_id = self.untracked.definitions.write().create_def(parent, data, disambiguator); + let def_id = self.untracked.definitions.write().create_def( + parent, + data, + disambiguator, + self.is_in_sandbox(), + ); // This function modifies `self.definitions` using a side-effect. // We need to ensure that these side effects are re-run by the incr. comp. engine. diff --git a/compiler/rustc_query_impl/src/callfront.rs b/compiler/rustc_query_impl/src/callfront.rs new file mode 100644 index 0000000000000..7cec4f7194edc --- /dev/null +++ b/compiler/rustc_query_impl/src/callfront.rs @@ -0,0 +1,5 @@ +use rustc_middle::ty::TyCtxt; + +pub(crate) fn hir_crate_items(tcx: TyCtxt<'_>) { + tcx.force_delayed_owners_lowering(); +} diff --git a/compiler/rustc_query_impl/src/dep_kind_vtables.rs b/compiler/rustc_query_impl/src/dep_kind_vtables.rs index d12db3784f711..4bb01bd422ecd 100644 --- a/compiler/rustc_query_impl/src/dep_kind_vtables.rs +++ b/compiler/rustc_query_impl/src/dep_kind_vtables.rs @@ -134,6 +134,7 @@ macro_rules! define_dep_kind_vtables { // Search for (QMODLIST) to find all occurrences of this query modifier list. arena_cache: $arena_cache:literal, cache_on_disk: $cache_on_disk:literal, + callfront: $callfront:literal, depth_limit: $depth_limit:literal, desc: $desc:expr, eval_always: $eval_always:literal, diff --git a/compiler/rustc_query_impl/src/execution.rs b/compiler/rustc_query_impl/src/execution.rs index ed9ad8c7a0a68..cf0a1117fe006 100644 --- a/compiler/rustc_query_impl/src/execution.rs +++ b/compiler/rustc_query_impl/src/execution.rs @@ -320,7 +320,11 @@ fn try_execute_query<'tcx, C: QueryCache, const INCR: bool>( // Delegate to another function to actually execute the query job. let (value, dep_node_index) = if INCR { - execute_job_incr(query, tcx, key, dep_node.unwrap(), id) + if tcx.is_in_sandbox() { + execute_job_non_incr(query, tcx, key, id) + } else { + execute_job_incr(query, tcx, key, dep_node.unwrap(), id) + } } else { execute_job_non_incr(query, tcx, key, id) }; @@ -648,6 +652,7 @@ pub(super) fn execute_query_incr_inner<'tcx, C: QueryCache>( if let Some(dep_node_index) = dep_node_index { tcx.dep_graph.read_index(dep_node_index) } + Some(result) } @@ -666,6 +671,7 @@ pub(crate) fn force_query_dep_node<'tcx, C: QueryCache>( return false; }; + query.callfront_fn.filter(|_| !tcx.is_in_sandbox()).inspect(|f| (f)(tcx)); ensure_sufficient_stack(|| { try_execute_query::(query, tcx, DUMMY_SP, key, Some(dep_node)) }); diff --git a/compiler/rustc_query_impl/src/lib.rs b/compiler/rustc_query_impl/src/lib.rs index d5133aa04dccc..4df7ee42fc4ac 100644 --- a/compiler/rustc_query_impl/src/lib.rs +++ b/compiler/rustc_query_impl/src/lib.rs @@ -18,7 +18,8 @@ use rustc_middle::ty::TyCtxt; pub use crate::dep_kind_vtables::make_dep_kind_vtables; pub use crate::execution::{CollectActiveJobsKind, collect_active_query_jobs}; pub use crate::job::{QueryJobMap, break_query_cycle, print_query_stack}; - +use crate::query_impl::for_each_query_vtable; +mod callfront; mod dep_kind_vtables; mod error; mod execution; @@ -60,9 +61,34 @@ pub fn query_system<'tcx>( } } +fn enter_sandbox<'tcx, C: QueryCache>(query: &'tcx QueryVTable<'tcx, C>) { + query.save_keys(); +} + +fn leave_sandbox<'tcx, C: QueryCache>(query: &'tcx QueryVTable<'tcx, C>) { + if query.name == "lower_delayed_owner" + || query.name == "delayed_owner" + || query.name == "def_kind" + { + return; + } + + query.invalidate_saved_keys(); +} + pub fn provide(providers: &mut rustc_middle::util::Providers) { providers.hooks.alloc_self_profile_query_strings = profiling_support::alloc_self_profile_query_strings; providers.hooks.verify_query_key_hashes = plumbing::verify_query_key_hashes; providers.hooks.encode_query_values = plumbing::encode_query_values; + providers.hooks.enter_query_sandbox = |tcx| { + for_each_query_vtable!(ALL, tcx, |query| { + enter_sandbox(query); + }); + }; + providers.hooks.leave_query_sandbox = |tcx| { + for_each_query_vtable!(ALL, tcx, |query| { + leave_sandbox(query); + }); + }; } diff --git a/compiler/rustc_query_impl/src/query_impl.rs b/compiler/rustc_query_impl/src/query_impl.rs index 4425acc6b86b8..0a82a0d1c49fb 100644 --- a/compiler/rustc_query_impl/src/query_impl.rs +++ b/compiler/rustc_query_impl/src/query_impl.rs @@ -18,6 +18,7 @@ macro_rules! define_queries { // Search for (QMODLIST) to find all occurrences of this query modifier list. arena_cache: $arena_cache:literal, cache_on_disk: $cache_on_disk:literal, + callfront: $callfront:literal, depth_limit: $depth_limit:literal, desc: $desc:expr, eval_always: $eval_always:literal, @@ -56,6 +57,12 @@ macro_rules! define_queries { key: Key<'tcx>, mode: QueryMode, ) -> Option>> { + #[cfg($callfront)] + { + let vtable = &tcx.query_system.query_vtables.$name; + vtable.callfront_fn.filter(|_| !tcx.is_in_sandbox()).inspect(|f| (f)(tcx)); + } + #[cfg(debug_assertions)] let _guard = tracing::span!(tracing::Level::TRACE, stringify!($name), ?key).entered(); crate::execution::execute_query_incr_inner( @@ -79,6 +86,12 @@ macro_rules! define_queries { key: Key<'tcx>, __mode: QueryMode, ) -> Option>> { + #[cfg($callfront)] + { + let vtable = &tcx.query_system.query_vtables.$name; + vtable.callfront_fn.filter(|_| !tcx.is_in_sandbox()).inspect(|f| (f)(tcx)); + } + Some(crate::execution::execute_query_non_incr_inner( &tcx.query_system.query_vtables.$name, tcx, @@ -200,6 +213,14 @@ macro_rules! define_queries { } else { crate::query_impl::$name::execute_query_non_incr::__rust_end_short_backtrace }, + + #[cfg($callfront)] + callfront_fn: Some(|tcx| { + $crate::callfront::$name(tcx); + }), + + #[cfg(not($callfront))] + callfront_fn: None, } } diff --git a/compiler/rustc_type_ir/src/search_graph/global_cache.rs b/compiler/rustc_type_ir/src/search_graph/global_cache.rs index 7e438fefffca0..f263ffe9d9a0b 100644 --- a/compiler/rustc_type_ir/src/search_graph/global_cache.rs +++ b/compiler/rustc_type_ir/src/search_graph/global_cache.rs @@ -107,4 +107,8 @@ impl GlobalCache { None } + + pub fn clear(&mut self) { + self.map.clear(); + } } diff --git a/tests/incremental/delegation/body-identity-glob.rs b/tests/incremental/delegation/body-identity-glob.rs new file mode 100644 index 0000000000000..07274e5aa55ec --- /dev/null +++ b/tests/incremental/delegation/body-identity-glob.rs @@ -0,0 +1,33 @@ +//@ run-pass +//@ revisions:rpass1 rpass2 + +#![feature(fn_delegation)] +#![allow(incomplete_features)] + +trait Trait { + fn foo(&self) {} + fn bar(&self) {} +} + +impl Trait for u8 {} + +struct S(u8); + +mod to_import { + pub fn check(arg: &u8) -> &u8 { arg } +} + +impl Trait for S { + reuse Trait::* { + use to_import::check; + + let _arr = Some(self.0).map(|x| [x * 2; 3]); + check(&self.0) + } +} + +fn main() { + let s = S(0); + s.foo(); + s.bar(); +} diff --git a/tests/incremental/delegation/body-identity-list.rs b/tests/incremental/delegation/body-identity-list.rs new file mode 100644 index 0000000000000..2517881ca6c0d --- /dev/null +++ b/tests/incremental/delegation/body-identity-list.rs @@ -0,0 +1,33 @@ +//@ run-pass +//@ revisions:rpass1 rpass2 + +#![feature(fn_delegation)] +#![allow(incomplete_features)] + +trait Trait { + fn foo(&self) {} + fn bar(&self) {} +} + +impl Trait for u8 {} + +struct S(u8); + +mod to_import { + pub fn check(arg: &u8) -> &u8 { arg } +} + +impl Trait for S { + reuse Trait::{foo, bar} { + use to_import::check; + + let _arr = Some(self.0).map(|x| [x * 2; 3]); + check(&self.0) + } +} + +fn main() { + let s = S(0); + s.foo(); + s.bar(); +} diff --git a/tests/incremental/delegation/explicit-paths-in-traits-pass.rs b/tests/incremental/delegation/explicit-paths-in-traits-pass.rs new file mode 100644 index 0000000000000..219261882d985 --- /dev/null +++ b/tests/incremental/delegation/explicit-paths-in-traits-pass.rs @@ -0,0 +1,28 @@ +//@ run-pass +//@ revisions:rpass1 rpass2 + +#![feature(fn_delegation)] +#![allow(incomplete_features)] + +trait ToReuse { + fn foo(&self, x: i32) -> i32 { x } + fn foo1(x: i32) -> i32 { x } +} + +fn foo2() -> i32 { 42 } + +trait Trait: ToReuse { + reuse ToReuse::foo; + reuse ::foo1; + reuse foo2; +} + +struct S; +impl ToReuse for S {} +impl Trait for S {} + +fn main() { + assert_eq!(::foo(&S, 1), 1); + assert_eq!(::foo1(1), 1); + assert_eq!(::foo2(), 42); +} diff --git a/tests/incremental/delegation/explicit-paths-pass.rs b/tests/incremental/delegation/explicit-paths-pass.rs new file mode 100644 index 0000000000000..c59145fe603f1 --- /dev/null +++ b/tests/incremental/delegation/explicit-paths-pass.rs @@ -0,0 +1,50 @@ +//@ run-pass +//@ revisions:rpass1 rpass2 + +#![feature(fn_delegation)] +#![allow(incomplete_features)] + +trait Trait { + fn bar(&self, x: i32) -> i32 { x } + fn description(&self) -> &str { + "hello world!" + } + fn static_method(x: i32) -> i32 { x } + fn static_method2(x: i32, y: i32) -> i32 { x + y } +} + +struct F; +impl Trait for F {} + +mod to_reuse { + pub fn foo(x: i32) -> i32 { x + 1 } +} + +struct S(F); +impl Trait for S { + reuse Trait::bar { self.0 } + reuse Trait::description { self.0 } + reuse ::static_method; + reuse ::static_method2 { S::static_method(self) } +} + +impl S { + reuse ::static_method { to_reuse::foo(self) } +} + +impl std::fmt::Display for S { + reuse ::fmt { self.description() } +} + +fn main() { + let s = S(F); + assert_eq!(42, s.bar(42)); + assert_eq!("hello world!", format!("{s}")); + assert_eq!(43, S::static_method(42)); + assert_eq!(42, ::static_method(42)); + assert_eq!(21, S::static_method2(10, 10)); + + #[inline] + reuse to_reuse::foo; + assert_eq!(43, foo(42)); +} diff --git a/tests/incremental/delegation/explicit-paths-signature-pass.rs b/tests/incremental/delegation/explicit-paths-signature-pass.rs new file mode 100644 index 0000000000000..e6e0b3d1e3025 --- /dev/null +++ b/tests/incremental/delegation/explicit-paths-signature-pass.rs @@ -0,0 +1,40 @@ +//@ run-pass +//@ revisions:rpass1 rpass2 + +#![feature(fn_delegation)] +#![allow(incomplete_features)] + +mod to_reuse { + use crate::S; + + pub fn foo<'a>(#[cfg(false)] a: u8, _b: &'a S) -> u32 { + 1 + } +} + +reuse to_reuse::foo; + +trait Trait { + fn foo(&self) -> u32 { 0 } + fn bar(self: Box) -> u32 { 2 } + fn baz(a: (i32, i32)) -> i32 { a.0 + a.1 } +} + +struct F; +impl Trait for F {} + +struct S(F); + +impl Trait for S { + reuse to_reuse::foo { self } + reuse Trait::bar { Box::new(self.0) } + reuse ::baz; +} + +fn main() { + let s = S(F); + assert_eq!(1, foo(&s)); + assert_eq!(1, s.foo()); + assert_eq!(2, Box::new(s).bar()); + assert_eq!(4, S::baz((2, 2))); +} diff --git a/tests/incremental/delegation/glob-glob.rs b/tests/incremental/delegation/glob-glob.rs new file mode 100644 index 0000000000000..b2746f43f25bb --- /dev/null +++ b/tests/incremental/delegation/glob-glob.rs @@ -0,0 +1,37 @@ +//@ run-pass +//@ revisions:rpass1 rpass2 + +#![feature(fn_delegation)] +#![allow(incomplete_features)] + +mod inner { + pub trait TraitFoo { + fn foo(&self) -> u8; + } + pub trait TraitBar { + fn bar(&self) -> u8; + } + + impl TraitFoo for u8 { + fn foo(&self) -> u8 { 0 } + } + impl TraitBar for u8 { + fn bar(&self) -> u8 { 1 } + } +} + +trait Trait { + fn foo(&self) -> u8; + fn bar(&self) -> u8; +} + +impl Trait for u8 { + reuse inner::TraitFoo::*; + reuse inner::TraitBar::*; +} + +fn main() { + let u = 0u8; + u.foo(); + u.bar(); +} diff --git a/tests/incremental/delegation/glob.rs b/tests/incremental/delegation/glob.rs new file mode 100644 index 0000000000000..15d43176b228f --- /dev/null +++ b/tests/incremental/delegation/glob.rs @@ -0,0 +1,36 @@ +//@ run-pass +//@ revisions:rpass1 rpass2 + +#![feature(fn_delegation)] +#![allow(incomplete_features)] + +trait Trait { + fn foo(&self) -> u8; + fn bar(&self) -> u8; +} + +impl Trait for u8 { + fn foo(&self) -> u8 { 0 } + fn bar(&self) -> u8 { 1 } +} + +struct S(u8); +struct Z(u8); + +impl Trait for S { + reuse Trait::* { &self.0 } +} + +impl Trait for Z { + reuse ::* { &self.0 } +} + +fn main() { + let s = S(2); + s.foo(); + s.bar(); + + let z = Z(3); + z.foo(); + z.bar(); +} diff --git a/tests/incremental/delegation/impl-reuse-pass.rs b/tests/incremental/delegation/impl-reuse-pass.rs new file mode 100644 index 0000000000000..483bcfd1d09b4 --- /dev/null +++ b/tests/incremental/delegation/impl-reuse-pass.rs @@ -0,0 +1,268 @@ +//@ run-pass +//@ revisions:rpass1 rpass2 + +#![allow(incomplete_features)] +#![feature(fn_delegation)] +#![feature(const_trait_impl)] +#![allow(warnings)] + +mod default { + trait T { + fn foo(&self) {} + fn bar(&self) {} + fn goo(&self) {} + } + + struct S; + impl T for S {} + + struct F(S); + reuse impl T for F { self.0 } + + fn f() { + let f = F(S{}); + + f.foo(); + f.bar(); + f.goo(); + } +} + +mod dyn_traits { + trait T { + fn foo(&self) -> Box; + } + + trait SecondTrait { + fn bar(&self); + } + + reuse impl SecondTrait for dyn T { self.foo().as_ref() } +} + +mod complex_path { + pub mod first { + pub mod second { + pub trait T { + fn foo(&self, x: usize); + } + } + } + + struct S; + impl first::second::T for S { + fn foo(&self, x: usize) { } + } + + struct F(S); + reuse impl first::second::T for F { self.0 } + + fn f() { + use complex_path::first::second::T; + + let f = F(S{}); + + f.foo(1); + } +} + +mod no_body_reuse { + trait T { + fn foo(&self) {} + fn bar(&mut self) {} + } + + struct F; + + reuse impl T for F; + + fn foo() { + let mut f = F{}; + + f.foo(); + f.bar(); + } +} + +mod unsafe_trait { + unsafe trait UnsafeTrait { + fn foo(&self) {} + fn bar(&self) {} + fn goo(&self) {} + } + + struct S; + unsafe impl UnsafeTrait for S {} + + struct F(S); + reuse unsafe impl UnsafeTrait for F { self.0 } + + fn f() { + let f = F(S{}); + + f.foo(); + f.bar(); + f.goo(); + } +} + +mod const_trait { + const trait ConstTrait { + fn foo(&self) -> usize { 0 } + fn bar(&self) -> usize { 1 } + } + + struct S; + const impl ConstTrait for S {} + + struct F(S); + reuse const impl ConstTrait for F { self.0 } + + fn f() { + let f = F(S{}); + + f.foo(); + f.bar(); + } +} + +mod different_selves { + trait T: Sized { + fn foo(&self) {} + fn boo(self) {} + fn goo(&mut self) {} + } + + struct S; + impl T for S {} + + struct F(S); + reuse impl T for F { self.0 } + + struct D(S); + macro_rules! self_0 { ($self:ident) => { $self.0 } } + + reuse impl T for D { self_0!(self) } + + fn f() { + let mut f = F(S{}); + f.foo(); + f.goo(); + f.boo(); + + let mut d = D(S{}); + d.foo(); + d.goo(); + d.boo(); + } +} + +mod macros { + trait Trait { + fn foo(&self) -> u8 { 0 } + fn bar(&self) -> u8 { 1 } + } + + impl Trait for u8 {} + struct S(u8); + + macro_rules! self_0_ref { ($self:ident) => { &$self.0 } } + + reuse impl Trait for S { self_0_ref!(self) } + + struct M(u8); + macro_rules! m { () => { M } } + reuse impl Trait for m!() { self_0_ref!(self) } + + fn f() { + let s = S(1); + s.foo(); + s.bar(); + + let m = M(41); + m.foo(); + m.bar(); + } +} + +mod generics { + trait Trait<'a, 'b, A, B, C> { + fn foo(&self, a: &A) {} + fn bar(&self, b: &B) {} + fn goo(&self, c: &C) {} + } + + struct S; + impl<'a, 'b, A, B, C> Trait<'a, 'b, A, B, C> for S {} + + struct F(S); + reuse impl<'a, 'b, A, B, C> Trait<'a, 'b, A, B, C> for F { &self.0 } + + struct S1; + struct F1(S1); + impl<'c, B> Trait<'static, 'c, usize, B, String> for S1 {} + reuse impl<'d, B> Trait<'static, 'd, usize, B, String> for F1 { &self.0 } + + struct S2; + struct F2(S2); + impl Trait<'static, 'static, u8, u16, u32> for S2 {} + reuse impl Trait<'static, 'static, u8, u16, u32> for F2 { &self.0 } + + fn f<'a, 'b, 'c, A, B, C>(a: A, b: B, c: C) { + let f = F(S{}); + + >::foo(&f, &a); + >::bar(&f, &b); + >::goo(&f, &c); + + let f = F1(S1{}); + >::foo(&f, &123); + >::bar(&f, &b); + >::goo(&f, &"s".to_string()); + + let f = F2(S2{}); + >::foo(&f, &1); + >::bar(&f, &2); + >::goo(&f, &3); + } +} + +mod reuse_in_different_places { + trait T { + fn foo(&self, x: usize) {} + } + + struct S; + impl T for S {} + + struct F1(S); + reuse impl T for F1 { + struct F2(S, S, S); + reuse impl T for F2 { self.1 } + + let f2 = F2(S{}, S{}, S{}); + f2.foo(123); + + &self.0 + } + + fn foo() { + struct F(S); + reuse impl T for F { self.0 } + + let f = F(S{}); + f.foo(1); + } + + fn bar() { + || { + struct F(S); + reuse impl T for F { self.0 } + + let f = F(S{}); + f.foo(1); + }; + } +} + +fn main() {} diff --git a/tests/incremental/delegation/impl-trait.rs b/tests/incremental/delegation/impl-trait.rs new file mode 100644 index 0000000000000..9e889f5da73c5 --- /dev/null +++ b/tests/incremental/delegation/impl-trait.rs @@ -0,0 +1,28 @@ +//@ run-pass +//@ revisions:rpass1 rpass2 + +#![feature(fn_delegation)] +#![allow(incomplete_features)] + +mod to_reuse { + pub fn foo() -> impl Clone { 0 } +} + +reuse to_reuse::foo; + +trait Trait { + fn bar() -> impl Clone { 1 } +} + +struct S; +impl Trait for S {} + +impl S { + reuse to_reuse::foo; + reuse ::bar; +} + +fn main() { + foo().clone(); + ::bar().clone(); +} diff --git a/tests/incremental/delegation/list.rs b/tests/incremental/delegation/list.rs new file mode 100644 index 0000000000000..11d195394feed --- /dev/null +++ b/tests/incremental/delegation/list.rs @@ -0,0 +1,47 @@ +//@ run-pass +//@ revisions:rpass1 rpass2 + +#![feature(fn_delegation)] +#![allow(incomplete_features)] + +trait Trait { + fn foo(&self) -> u8 { 0 } + fn bar(&self) -> u8 { 1 } +} + +impl Trait for u8 {} + +struct S(u8); +struct Z(u8); + +impl Trait for S { + reuse Trait::{foo, bar} { &self.0 } +} + +impl Trait for Z { + reuse ::{foo, bar} { &self.0 } +} + +trait Trait2 where Self: Trait { + reuse Trait::{foo, bar}; +} + +mod to_reuse { + pub fn a() {} + pub fn b() {} +} + +reuse to_reuse::{a, b}; + +fn main() { + let s = S(2); + s.foo(); + s.bar(); + + let z = Z(3); + z.foo(); + z.bar(); + + a(); + b(); +} diff --git a/tests/incremental/delegation/macro-inside-glob.rs b/tests/incremental/delegation/macro-inside-glob.rs new file mode 100644 index 0000000000000..dbeafc0806e48 --- /dev/null +++ b/tests/incremental/delegation/macro-inside-glob.rs @@ -0,0 +1,27 @@ +//@ run-pass +//@ revisions:rpass1 rpass2 + +#![feature(fn_delegation)] +#![allow(incomplete_features)] + +trait Trait { + fn foo(&self) -> u8 { 0 } + fn bar(&self) -> u8 { 1 } +} + +impl Trait for u8 {} + +struct S(u8); + +// Macro expansion works inside delegation items. +macro_rules! u8 { () => { u8 } } +macro_rules! self_0 { ($self:ident) => { &$self.0 } } +impl Trait for S { + reuse ::* { self_0!(self) } +} + +fn main() { + let s = S(2); + s.foo(); + s.bar(); +} diff --git a/tests/incremental/delegation/macro-inside-list.rs b/tests/incremental/delegation/macro-inside-list.rs new file mode 100644 index 0000000000000..9a2f6c462eb8f --- /dev/null +++ b/tests/incremental/delegation/macro-inside-list.rs @@ -0,0 +1,27 @@ +//@ run-pass +//@ revisions:rpass1 rpass2 + +#![feature(fn_delegation)] +#![allow(incomplete_features)] + +trait Trait { + fn foo(&self) -> u8 { 0 } + fn bar(&self) -> u8 { 1 } +} + +impl Trait for u8 {} + +struct S(u8); + +// Macro expansion works inside delegation items. +macro_rules! u8 { () => { u8 } } +macro_rules! self_0 { ($self:ident) => { &$self.0 } } +impl Trait for S { + reuse ::{foo, bar} { self_0!(self) } +} + +fn main() { + let s = S(2); + s.foo(); + s.bar(); +} diff --git a/tests/incremental/delegation/mapping/free-to-free-pass.rs b/tests/incremental/delegation/mapping/free-to-free-pass.rs new file mode 100644 index 0000000000000..dc7db7a78c90f --- /dev/null +++ b/tests/incremental/delegation/mapping/free-to-free-pass.rs @@ -0,0 +1,148 @@ +//@ run-pass +//@ revisions:rpass1 rpass2 + +#![feature(fn_delegation)] +#![allow(incomplete_features)] + +//! This is one of the mapping tests, which tests mapping of delegee parent and child +//! generic params, whose main goal is to create cases with +//! different number of lifetimes/types/consts in delegee child and parent; and in +//! delegation parent if applicable. At some tests predicates are +//! added. At some tests user-specified args are specified in reuse statement. + +// Testing lifetimes + types + consts, reusing with(out) +// user args, checking predicates inheritance, testing with impl Traits +mod test_1 { + trait Bound1 {} + trait Bound2 {} + trait Bound3 {} + + struct X {} + + impl Bound1 for X {} + impl Bound2 for X {} + impl Bound3 for X {} + + fn foo<'a: 'a, 'b: 'b, T: Clone, U: Clone, const N: usize>( + _x: impl Bound1 + Bound2 + Bound3, + _f: impl FnOnce(T) -> U, + ) { + } + + pub fn check() { + reuse foo as bar; + bar::(X {}, |x| x); + + reuse foo::<'static, 'static, usize, String, 132> as bar1; + + bar1(X {}, |x| x.to_string()); + } +} + +// Testing lifetimes + types + consts, reusing without user args, +// providing delegation parent args in invocation +mod test_2 { + fn foo<'a: 'a, 'b: 'b, T: Clone, U: Clone, const N: usize>() {} + + pub fn check() { + reuse foo as bar; + bar::(); + } +} + +// Testing lifetimes + types + consts, reusing without user args, +// providing random types with delegation parent generics specified +mod test_3 { + fn foo<'a: 'a, 'b: 'b, T: Clone, U: Clone, const N: usize>() {} + + pub fn check() { + reuse foo as bar; + bar::(); + } +} + +// Testing late-bound lifetimes + types + consts, reusing without user args, +// providing random types with delegation parent generics specified, +// checking signature inheritance +mod test_4 { + fn foo<'a, 'b, T: Clone, U: Clone, const N: usize>(_t: &'a T, _u: &'b U) {} + + pub fn check() { + reuse foo as bar; + bar::(&1, &2); + } +} + +// Testing late-bound lifetimes + types + consts, reusing without user args, +// providing random types with delegation parent generics specified, +// checking signature inheritance, testing mixed order of types and consts +mod test_5 { + fn foo<'a, 'b, T: Clone, const N: usize, U: Clone>(_t: &'a T, _u: &'b U) {} + + pub fn check() { + reuse foo as bar; + bar::(&1, &2); + } +} + +// Testing late-bound lifetimes + types + consts, reusing with user args, +// checking signature inheritance, testing mixed order of types and consts +mod test_6 { + fn foo<'a, 'b, T: Clone, const N: usize, U: Clone>(_t: &'a T, _u: &'b U) {} + + pub fn check() { + reuse foo:: as bar; + bar(&"".to_string(), &"".to_string()); + } +} + +mod test_7 { + fn foo(t: T, u: U, f: impl FnOnce(T, U) -> U) -> U { + f(t, u) + } + + pub fn check() { + reuse foo as bar; + assert_eq!(bar::(1, 2, |_, y| y), 2); + } +} + +// Testing reuse of local fn with delegation parent generic params specified, +// late-bound lifetimes + types + consts, reusing with user args, +// checking signature inheritance, mixed consts and types ordering +mod test_8 { + pub fn check() { + fn foo<'a, 'b, const N: usize, T: Clone, U: Clone>(_t: &'a T, _u: &'b U) {} + + reuse foo::<1, String, String> as bar; + bar(&"".to_string(), &"".to_string()); + } +} + +// Testing reuse of local fn inside closure, +// late-bound lifetimes + types + consts, reusing with user args, +// checking signature inheritance, mixed consts and types ordering +mod test_9 { + pub fn check() { + let closure = || { + fn foo<'a, 'b, T: Clone, const N: usize, U: Clone>(_t: &'a T, _u: &'b U) {} + + reuse foo:: as bar; + bar(&"".to_string(), &"".to_string()); + }; + + closure(); + } +} + +pub fn main() { + test_1::check(); + test_2::check::(); + test_3::check::(); + test_4::check::(); + test_5::check::(); + test_6::check::(); + test_7::check(); + test_8::check::(); + test_9::check::(); +} diff --git a/tests/incremental/delegation/mapping/free-to-trait-pass.rs b/tests/incremental/delegation/mapping/free-to-trait-pass.rs new file mode 100644 index 0000000000000..b1f35f588ae78 --- /dev/null +++ b/tests/incremental/delegation/mapping/free-to-trait-pass.rs @@ -0,0 +1,248 @@ +//@ run-pass +//@ revisions:rpass1 rpass2 + +#![feature(fn_delegation)] +#![allow(incomplete_features)] + +//! This is one of the mapping tests, which tests mapping of delegee parent and child +//! generic params, whose main goal is to create cases with +//! different number of lifetimes/types/consts in delegee child and parent; and in +//! delegation parent if applicable. At some tests predicates are +//! added. At some tests user-specified args are specified in reuse statement. + +// Testing lifetimes + types + consts in both parent and child, reusing in +// a function without generic params, with impl traits +mod test_1 { + trait Trait<'b, 'c, 'a, T, const N: usize>: Sized { + fn foo<'d: 'd, U, const M: bool>(self, _f: impl FnOnce() -> ()) {} + } + + impl Trait<'static, 'static, 'static, i32, 1> for u8 {} + + pub fn check() { + fn no_ctx() { + reuse Trait::foo as bar; + bar::<'static, 'static, 'static, 'static, u8, i32, 1, String, true>(123, || ()); + } + + fn with_ctx<'a, 'b, 'c, A, B, C, const N: usize, const M: bool>() { + reuse Trait::foo as bar; + bar::<'static, 'static, 'static, 'a, u8, i32, 1, A, M>(123, || ()); + } + + no_ctx(); + with_ctx::(); + } +} + +// Testing lifetimes + types + consts in both parent and child, add user-specified args to parent +mod test_2 { + trait Trait<'a, T, const N: usize>: Sized { + fn foo<'b: 'b, U, const M: bool>(self) {} + } + + impl Trait<'static, i32, 1> for u8 {} + + pub fn check() { + reuse Trait::<'static, i32, 1>::foo as bar; + + bar::<'static, u8, String, true>(123); + } +} + +// Testing lifetimes + types + consts in both parent and child, +// add user-specified args to child +mod test_3 { + trait Trait<'a, T, const N: usize>: Sized { + fn foo<'b: 'b, U, const M: bool>(self) {} + } + + impl Trait<'static, String, 1> for u8 {} + + pub fn check() { + reuse Trait::foo::<'static, i32, true> as bar; + + bar::<'static, u8, String, 1>(123); + } +} + +// Testing types/consts in parent, lifetimes + types/consts in child, +// add user-specified args to child +mod test_4 { + trait Trait: Sized { + fn foo<'b: 'b, U, const M: bool>(self) {} + } + + impl Trait for u8 {} + + pub fn check() { + reuse Trait::foo::<'static, i32, true> as bar; + + bar::(123); + } +} + +// Testing consts in parent, lifetimes + types/consts in child, add user-specified args to child +mod test_5 { + trait Trait: Sized { + fn foo<'b: 'b, U, const M: bool>(self) {} + } + + impl Trait<1> for u8 {} + + pub fn check() { + reuse Trait::foo::<'static, i32, true> as bar; + + bar::(123); + } +} + +// Testing no generics in parent, lifetimes + types/consts in child, +// add user-specified args to child +mod test_6 { + trait Trait: Sized { + fn foo<'b: 'b, U, const M: bool>(self) {} + } + + impl Trait for u8 {} + + pub fn check() { + reuse Trait::foo::<'static, i32, true> as bar; + + bar::(123); + } +} + +// Testing lifetimes + types/consts in parent, types/consts in child, +// add user-specified args to parent +mod test_7 { + trait Trait<'a, T, const N: usize>: Sized { + fn foo(self) {} + } + + impl Trait<'static, i32, 1> for u8 {} + + pub fn check() { + reuse Trait::<'static, i32, 1>::foo as bar; + + bar::(123); + } +} + +// Testing lifetimes + types/consts in parent, consts in child, add user-specified args to parent +mod test_8 { + trait Trait<'a, T, const N: usize>: Sized { + fn foo(self) {} + } + + impl Trait<'static, i32, 1> for u8 {} + + pub fn check() { + reuse Trait::<'static, i32, 1>::foo as bar; + + bar::(123); + } +} + +// Testing lifetimes + types/consts in parent, none in child, add user-specified args to parent +mod test_9 { + trait Trait<'a, T, const N: usize>: Sized { + fn foo(self) {} + } + + impl Trait<'static, i32, 1> for u8 {} + + pub fn check() { + reuse Trait::<'static, i32, 1>::foo as bar; + + bar::(123); + } +} + +// Testing lifetimes + types in parent, lifetimes + types/consts in child, +// adding self ty to reuse, testing using generic params from delegation parent +// context, adding user-specified args to none, parent, parent and child +mod test_10 { + trait Trait<'b, 'c, T> { + fn foo<'d: 'd, U, const M: bool>() {} + } + + impl<'b, 'c, T> Trait<'b, 'c, T> for u8 {} + + pub fn check() { + fn with_ctx<'a, 'b, 'c, A, B, C, const N: usize, const M: bool>() { + reuse ::foo as bar; + bar::<'a, 'b, 'c, u8, C, A, M>(); + bar::<'static, 'static, 'static, u8, i32, i32, false>(); + + reuse >::foo as bar1; + bar1::<'static, u8, i32, true>(); + + reuse >::foo::<'static, u32, true> as bar2; + bar2::(); + } + + with_ctx::(); + } +} + +// Testing lifetimes + types in parent, lifetimes + types/consts in child, +// adding self ty to reuse, testing using generic params from delegation parent +// context, testing predicates inheritance +mod test_11 { + trait Bound0 {} + trait Bound1 {} + trait Bound2 {} + + trait Trait<'a: 'static, T, P> + where + Self: Sized, + T: Bound0, + P: Bound2>>>, + { + fn foo<'d: 'd, U: Bound1, const M: bool>() {} + } + + impl Bound0 for u32 {} + impl Bound1 for String {} + impl<'a: 'static, T: Bound0, P: Bound2>>>> Trait<'a, T, P> for usize {} + + struct Struct; + impl Bound2>>> for Struct {} + + pub fn check<'b>() { + reuse ::foo; + foo::<'static, 'b, usize, u32, Struct, String, false>(); + } +} + +// Testing lifetimes + types/consts in parent with defaults, none in child, +// reuse without user-specified args +mod test_12 { + trait Trait<'a, T = usize, const N: usize = 123>: Sized { + fn foo(self) {} + } + + impl Trait<'static, i32, 1> for u8 {} + + pub fn check() { + reuse Trait::foo as bar; + + bar::(123); + } +} + +pub fn main() { + test_1::check(); + test_2::check(); + test_3::check(); + test_4::check(); + test_5::check(); + test_6::check(); + test_7::check(); + test_8::check(); + test_9::check(); + test_10::check(); + test_11::check(); + test_12::check(); +} diff --git a/tests/incremental/delegation/mapping/impl-trait-to-free-pass.rs b/tests/incremental/delegation/mapping/impl-trait-to-free-pass.rs new file mode 100644 index 0000000000000..5e17e9b1a22e0 --- /dev/null +++ b/tests/incremental/delegation/mapping/impl-trait-to-free-pass.rs @@ -0,0 +1,264 @@ +//@ run-pass +//@ revisions:rpass1 rpass2 + +#![feature(fn_delegation)] +#![allow(incomplete_features)] +#![allow(late_bound_lifetime_arguments)] + +//! This is one of the mapping tests, which tests mapping of delegee parent and child +//! generic params, whose main goal is to create cases with +//! different number of lifetimes/types/consts in delegee child and parent; and in +//! delegation parent if applicable. At some tests predicates are +//! added. At some tests user-specified args are specified in reuse statement. + +// Testing lifetimes + types/consts in child reuses, with impl traits, +// with (un)specified user args with additional generic params in delegation parent +mod test_1 { + mod to_reuse { + pub fn foo<'a: 'a, 'b: 'b, A, B, const N: usize>() {} + pub fn bar<'a: 'a, 'b: 'b, A, B, const N: usize>(_x: &super::XX, _f: impl FnOnce(A) -> B) {} + } + + trait Trait<'a, 'b, 'c, A, B, const N: usize>: Sized { + fn foo<'x: 'x, 'y: 'y, AA, BB, const NN: usize>() {} + fn bar<'x: 'x, 'y: 'y, AA, BB, const NN: usize>(&self, _f: impl FnOnce(AA) -> BB) {} + fn oof() {} + fn rab(&self, _f: impl FnOnce(A) -> B) {} + } + + #[allow(dead_code)] // Fields are used instead of phantom data for generics use + struct X<'x1, 'x2, 'x3, 'x4, X1, X2, const X3: usize>( + &'x1 X1, &'x2 X2, &'x3 X1, &'x4 [usize; X3]); + type XX = X::<'static, 'static, 'static, 'static, i32, i32, 3>; + + impl<'a, 'b, 'c, A, B, const N: usize> Trait<'a, 'b, 'c, A, B, N> for XX { + reuse to_reuse::foo; + reuse to_reuse::bar; + + reuse to_reuse::foo::<'a, 'c, A, String, 322> as oof; + reuse to_reuse::bar::<'a, 'c, A, B, 223> as rab; + } + + pub fn check() { + let x = X(&1, &2, &3, &[1, 2, 3]); + + > + ::foo::<'static, 'static, i8, i16, 123>(); + > + ::bar::<'static, 'static, String, i16, 123>(&x, |_| 123); + >::oof(); + >::rab(&x, |_| 123.to_string()); + } +} + +// Testing types/consts in child reuses, +// with (un)specified user args, with additional generic params in delegation parent +mod test_2 { + mod to_reuse { + pub fn foo() {} + pub fn bar(_x: &super::X) {} + } + + trait Trait<'a, 'b, 'c, A, B, const N: usize>: Sized { + fn foo() {} + fn bar(&self) {} + fn oof() {} + fn rab(&self) {} + } + + struct X; + impl<'a, A, B, const N: usize> Trait<'a, 'static, 'static, A, B, N> for X { + reuse to_reuse::foo; + reuse to_reuse::bar; + + reuse to_reuse::foo:: as oof; + reuse to_reuse::bar:: as rab; + } + + pub fn check() { + >::foo::(); + >::bar::(&X); + >::oof(); + >::rab(&X); + } +} + +// Testing none in child reuses, with unspecified user args, +// with additional generic params in delegation parent +mod test_3 { + mod to_reuse { + pub fn foo() {} + pub fn bar(_x: &super::X) {} + } + + trait Trait<'a, 'b, 'c, A, B, const N: usize>: Sized { + fn foo() {} + fn bar(&self) {} + } + + struct X; + impl<'a, A, B, const N: usize> Trait<'a, 'static, 'static, A, B, N> for X { + reuse to_reuse::foo; + reuse to_reuse::bar; + } + + pub fn check() { + >::foo(); + >::bar(&X); + } +} + +// Testing lifetimes + types/consts in child reuses, +// with (un)specified user args, with additional generic params in delegation parent +mod test_4 { + mod to_reuse { + pub fn foo<'a: 'a, 'b: 'b, A, B, const N: usize>() {} + pub fn bar<'a: 'a, 'b: 'b, A, B, const N: usize>(_x: &super::X) {} + } + + trait Trait: Sized { + fn foo<'x: 'x, 'y: 'y, AA, BB, const NN: usize>() {} + fn bar<'x: 'x, 'y: 'y, AA, BB, const NN: usize>(&self) {} + fn oof() {} + fn rab(&self) {} + } + + struct X; + impl<'a, 'c, A, B, const N: usize> Trait for X { + reuse to_reuse::foo; + reuse to_reuse::bar; + + reuse to_reuse::foo::<'a, 'c, A, String, 322> as oof; + reuse to_reuse::bar::<'a, 'c, i32, B, 223> as rab; + } + + pub fn check() { + >::foo::<'static, 'static, i8, i16, 123>(); + >::bar::<'static, 'static, X, i16, 123>(&X); + >::oof(); + >::rab(&X); + } +} + +// Testing lifetimes + types/consts in child reuses, +// with (un)specified user args, with additional generic params in delegation parent +mod test_5 { + mod to_reuse { + pub fn foo<'a: 'a, 'b: 'b, A, B, const N: usize>() {} + pub fn bar<'a: 'a, 'b: 'b, A, B, const N: usize>(_x: &super::X::) {} + } + + trait Trait: Sized { + fn foo<'x: 'x, 'y: 'y, AA, BB, const NN: usize>() {} + fn oof() {} + fn rab(&self) {} + } + + struct X(A, B); + impl<'a, 'c, A, B> Trait for X { + reuse to_reuse::foo; + + reuse to_reuse::foo::<'a, 'c, A, B, 322> as oof; + reuse to_reuse::bar::<'a, 'c, A, B, 223> as rab; + } + + pub fn check() { + as Trait>::foo::<'static, 'static, i8, i16, 123>(); + as Trait>::oof(); + as Trait>::rab(&X(1, 2)); + } +} + +// Testing types/consts in child reuses, +// with (un)specified user args, with additional generic params in delegation parent +mod test_6 { + mod to_reuse { + pub fn foo() {} + pub fn bar(_x: &super::X) {} + } + + trait Trait: Sized { + fn foo() {} + fn bar(&self) {} + fn oof() {} + fn rab(&self) {} + } + + struct X; + impl<'a, 'c, A, B, const N: usize> Trait for X { + reuse to_reuse::foo; + reuse to_reuse::bar; + + reuse to_reuse::foo:: as oof; + reuse to_reuse::bar:: as rab; + } + + pub fn check() { + >::foo::(); + >::bar::(&X); + >::oof(); + >::rab(&X); + } +} + +// Testing none in child reuses, with unspecified user args, +// with additional generic params in delegation parent +mod test_7 { + mod to_reuse { + pub fn foo() {} + pub fn bar(_x: &super::X) {} + } + + trait Trait: Sized { + fn foo() {} + fn bar(&self) {} + } + + struct X; + impl<'a, 'c, A, B, const N: usize> Trait for X { + reuse to_reuse::foo; + reuse to_reuse::bar; + } + + pub fn check() { + >::foo(); + >::bar(&X); + } +} + +// Testing none in child reuses, with unspecified user args +mod test_8 { + mod to_reuse { + pub fn foo() {} + pub fn bar(_x: &super::X) {} + } + + trait Trait: Sized { + fn foo() {} + fn bar(&self) {} + } + + struct X; + impl Trait for X { + reuse to_reuse::foo; + reuse to_reuse::bar; + } + + pub fn check() { + ::foo(); + ::bar(&X); + X::foo(); + X::bar(&X); + } +} + +fn main() { + test_1::check(); + test_2::check(); + test_3::check(); + test_4::check(); + test_5::check(); + test_6::check(); + test_7::check(); + test_8::check(); +} diff --git a/tests/incremental/delegation/mapping/impl-trait-to-trait-pass.rs b/tests/incremental/delegation/mapping/impl-trait-to-trait-pass.rs new file mode 100644 index 0000000000000..44c7906fa269f --- /dev/null +++ b/tests/incremental/delegation/mapping/impl-trait-to-trait-pass.rs @@ -0,0 +1,250 @@ +//@ run-pass +//@ revisions:rpass1 rpass2 + +#![feature(fn_delegation)] +#![allow(incomplete_features)] +#![allow(late_bound_lifetime_arguments)] + +//! This is one of the mapping tests, which tests mapping of delegee parent and child +//! generic params, whose main goal is to create cases with +//! different number of lifetimes/types/consts in delegee child and parent; and in +//! delegation parent if applicable. At some tests predicates are +//! added. At some tests user-specified args are specified in reuse statement. + +// Testing types in parent, types in child reuse, +// testing predicates inheritance, +// with additional generic params in delegation parent, with impl traits +mod test_1 { + trait Trait0 {} + + trait Trait1 { + fn foo(&self, _f: impl FnOnce(T, U) -> (U, T)) + where + T: Trait0, + U: Trait0, + { + } + } + + struct F; + impl Trait1 for F {} + + #[allow(dead_code)] // Fields are used instead of phantom data for generics use + struct S<'a, 'b, 'c, A, B>(F, &'a A, &'b B, &'c B); + + impl<'a, 'b, 'c, T, A, B> Trait1 for S<'a, 'b, 'c, A, B> { + reuse Trait1::::foo { &self.0 } + } + + impl Trait0 for u16 {} + + pub fn check() { + let s = S(F, &123, &123, &123); + as Trait1>::foo::(&s, |x, y| (y, x)); + } +} + +// Testing none in parent, none in child reuse, +// with additional generic params in delegation parent +mod test_2 { + trait Trait { + fn foo(&self) {} + } + + struct F; + impl Trait for F {} + + #[allow(dead_code)] // Fields are used instead of phantom data for generics use + struct S<'a, 'b, 'c, A, B, const C: bool>(F, &'a A, &'b B, &'c B); + + impl<'a, 'b, 'c, A, B, const C: bool> Trait for S<'a, 'b, 'c, A, B, C> { + reuse Trait::foo { &self.0 } + } + + pub fn check() { + let s = S(F, &123, &123, &123); + as Trait>::foo(&s); + } +} + +// Testing lifetimes + types in parent, none in child reuse, +// with additional generic params in delegation parent +mod test_3 { + trait Trait<'a, 'b, 'c, X, Y, Z> { + fn foo(&self) {} + } + + struct F; + impl<'a, 'b, 'c, X, Y, Z> Trait<'a, 'b, 'c, X, Y, Z> for F {} + + #[allow(dead_code)] // Fields are used instead of phantom data for generics use + struct S<'a, 'b, 'c, A, B, const C: bool>(F, &'a A, &'b B, &'c B); + + impl<'a, 'b, 'c, A, B, const C: bool> Trait<'a, 'b, 'static, A, String, bool> + for S<'a, 'b, 'c, A, B, C> { + reuse Trait::<'a, 'b, 'static, A, String, bool>::foo { &self.0 } + } + + pub fn check() { + let s = S(F, &123, &123, &123); + + as Trait<'static, 'static, 'static, i32, String, bool>>::foo(&s); + } +} + +// Testing lifetimes + types in parent, lifetimes + types/consts in child reuse, +// with additional generic params in delegation parent +mod test_4 { + trait Trait<'a, 'b, 'c, X, Y, Z> { + fn foo<'x: 'x, 'y: 'y, 'z: 'z, A, B, C, const XX: usize>(&self) {} + } + + struct F; + impl<'a, 'b, 'c, X, Y, Z> Trait<'a, 'b, 'c, X, Y, Z> for F {} + + #[allow(dead_code)] // Fields are used instead of phantom data for generics use + struct S<'a, 'b, 'c, A, B, const C: bool>(F, &'a A, &'b B, &'c B); + + impl<'a, 'b, 'c, A, B, const C: bool> Trait<'a, 'b, 'static, A, String, bool> + for S<'a, 'b, 'c, A, B, C> { + reuse Trait::<'a, 'b, 'static, A, String, bool>::foo { &self.0 } + } + + pub fn check() { + let s = S(F, &123, &123, &123); + + as Trait<'static, 'static, 'static, i32, String, bool>> + ::foo::<'static, 'static, 'static, i32, i32, i32, 1>(&s); + } +} + +// Testing types in parent, lifetimes in child reuse +// with additional generic params in delegation parent +mod test_5 { + trait Trait { + fn foo<'a: 'a, 'b: 'b, 'c: 'c>(&self) {} + } + + struct F; + impl Trait for F {} + + #[allow(dead_code)] // Fields are used instead of phantom data for generics use + struct S<'a, 'b, 'c, A, B, const C: bool>(F, &'a A, &'b B, &'c B); + + impl<'a, 'b, 'c, A, B, const C: bool> Trait for S<'a, 'b, 'c, A, B, C> { + reuse Trait::::foo { &self.0 } + } + + pub fn check() { + let s = S(F, &123, &123, &123); + as Trait> + ::foo::<'static, 'static, 'static>(&s); + as Trait>::foo(&s); + } +} + +// Testing types in parent, types in child reuse +// with additional generic params in delegation parent +mod test_6 { + trait Trait { + fn foo(&self) {} + } + + struct F; + impl Trait for F {} + + #[allow(dead_code)] // Fields are used instead of phantom data for generics use + struct S<'a, 'b, 'c, A, B, const C: bool>(F, &'a A, &'b B, &'c B); + + impl<'a, 'b, 'c, A, B, const C: bool> Trait for S<'a, 'b, 'c, A, B, C> { + reuse Trait::::foo { &self.0 } + } + + pub fn check() { + let s = S(F, &123, &123, &123); + as Trait>::foo::(&s); + } +} + +// Testing types in parent, none in child reuse +// with additional generic params in delegation parent +mod test_7 { + trait Trait { + fn foo(&self) {} + } + + struct F; + impl Trait for F {} + + #[allow(dead_code)] // Fields are used instead of phantom data for generics use + struct S<'a, 'b, 'c, A, B, const C: bool>(F, &'a A, &'b B, &'c B); + + impl<'a, 'b, 'c, A, B, const C: bool> Trait for S<'a, 'b, 'c, A, B, C> { + reuse Trait::::foo { &self.0 } + } + + pub fn check() { + let s = S(F, &123, &123, &123); + as Trait>::foo(&s); + } +} + +// Testing lifetimes in parent, none in child reuse +// with additional generic params in delegation parent +mod test_8 { + trait Trait<'a, 'b, 'c> { + fn foo(&self) {} + } + + struct F; + impl<'a, 'b, 'c> Trait<'a, 'b, 'c> for F {} + + #[allow(dead_code)] // Fields are used instead of phantom data for generics use + struct S<'a, 'b, 'c, A, B, const C: bool>(F, &'a A, &'b B, &'c B); + + impl<'a, 'b, 'c, A, B, const C: bool> Trait<'a, 'b, 'c> for S<'a, 'b, 'c, A, B, C> { + reuse Trait::<'a, 'static, 'b>::foo { &self.0 } + } + + pub fn check() { + let s = S(F, &123, &123, &123); + as Trait<'static, 'static, 'static>>::foo(&s); + } +} + +// Testing lifetimes in parent, lifetimes in child reuse +// with additional generic params in delegation parent +mod test_9 { + trait Trait<'a, 'b, 'c> { + fn foo<'x: 'x, 'y: 'y>(&self) {} + } + + struct F; + impl<'a, 'b, 'c> Trait<'a, 'b, 'c> for F {} + + #[allow(dead_code)] // Fields are used instead of phantom data for generics use + struct S<'a, 'b, 'c, A, B, const C: bool>(F, &'a A, &'b B, &'c B); + + impl<'a, 'b, 'c, A, B, const C: bool> Trait<'a, 'b, 'c> for S<'a, 'b, 'c, A, B, C> { + reuse Trait::<'a, 'static, 'b>::foo { &self.0 } + } + + pub fn check() { + let s = S(F, &123, &123, &123); + as Trait<'static, 'static, 'static>>::foo(&s); + as Trait<'static, 'static, 'static>> + ::foo::<'static, 'static>(&s); + } +} + +fn main() { + test_1::check(); + test_2::check(); + test_3::check(); + test_4::check(); + test_5::check(); + test_6::check(); + test_7::check(); + test_8::check(); + test_9::check(); +} diff --git a/tests/incremental/delegation/mapping/inherent-impl-to-free-pass.rs b/tests/incremental/delegation/mapping/inherent-impl-to-free-pass.rs new file mode 100644 index 0000000000000..963c1e292d76b --- /dev/null +++ b/tests/incremental/delegation/mapping/inherent-impl-to-free-pass.rs @@ -0,0 +1,126 @@ +//@ run-pass +//@ revisions:rpass1 rpass2 + +#![feature(fn_delegation)] +#![allow(incomplete_features)] + +//! This is one of the mapping tests, which tests mapping of delegee parent and child +//! generic params, whose main goal is to create cases with +//! different number of lifetimes/types/consts in delegee child and parent; and in +//! delegation parent if applicable. At some tests predicates are +//! added. At some tests user-specified args are specified in reuse statement. + +// Testing lifetimes + types/consts OR types/consts OR none in delegation parent, +// lifetimes + types/consts in child reuse, +// with(out) user-specified args, with impl traits +mod test_1 { + mod to_reuse { + pub fn foo<'a: 'a, 'b: 'b, A, B, const N: usize>(_f: impl FnOnce(A, B) -> B) {} + } + + #[allow(dead_code)] // Fields are used instead of phantom data for generics use + struct X1<'a, 'b, T, X, const N: usize>(&'a T, &'b X, &'a [i32; N]); + impl<'a, 'b, T, E, const N: usize> X1<'a, 'b, T, E, N> { + reuse to_reuse::foo; + reuse to_reuse::foo::<'static, 'static, i32, String, 1> as bar; + } + + #[allow(dead_code)] // Fields are used instead of phantom data for generics use + struct X2(T, X, &'static [i32; N]); + impl X2 { + reuse to_reuse::foo; + reuse to_reuse::foo::<'static, 'static, i32, String, 1> as bar; + } + + struct X3; + impl X3 { + reuse to_reuse::foo; + reuse to_reuse::foo::<'static, 'static, i32, String, 1> as bar; + } + + pub fn check() { + X1::<'static, 'static, i32, i32, 1> + ::foo::<'static, 'static, String, String, 123>(|_, y| y); + X1::<'static, 'static, i32, i32, 1>::bar(|_, y| y); + + X2::::foo::<'static, 'static, String, String, 123>(|_, y| y); + X2::::bar(|_, y| y); + + X3::foo::<'static, 'static, String, String, 123>(|_, y| y); + X3::bar(|_, y| y); + } +} + +// Testing lifetimes + types/consts OR types/consts OR none in parent, +// types/consts in child reuse, with(out) user-specified args +mod test_2 { + fn foo() {} + + #[allow(dead_code)] // Fields are used instead of phantom data for generics use + struct X1<'a, 'b, T, X, const N: usize>(&'a T, &'b X, &'a [i32; N]); + impl<'a, 'b, T, E, const N: usize> X1<'a, 'b, T, E, N> { + reuse foo; + reuse foo:: as bar; + } + + #[allow(dead_code)] // Fields are used instead of phantom data for generics use + struct X2(T, X, &'static [i32; N]); + impl X2 { + reuse foo; + reuse foo:: as bar; + } + + struct X3; + impl X3 { + reuse foo; + reuse foo:: as bar; + } + + pub fn check() { + X1::<'static, 'static, i32, i32, 1>::foo::(); + X1::<'static, 'static, i32, i32, 1>::bar(); + + X2::::foo::(); + X2::::bar(); + + X3::foo::(); + X3::bar(); + } +} + +// Testing lifetimes + types/consts OR types/consts OR none in parent, +// none in child reuse +mod test_3 { + fn foo() {} + + #[allow(dead_code)] // Fields are used instead of phantom data for generics use + struct X1<'a, 'b, T, X, const N: usize>(&'a T, &'b X, &'a [i32; N]); + impl<'a, 'b, T, E, const N: usize> X1<'a, 'b, T, E, N> { + reuse foo; + } + + #[allow(dead_code)] // Fields are used instead of phantom data for generics use + struct X2(T, X, &'static [i32; N]); + impl X2 { + reuse foo; + } + + struct X3; + impl X3 { + reuse foo; + } + + pub fn check() { + X1::<'static, 'static, i32, i32, 1>::foo(); + + X2::::foo(); + + X3::foo(); + } +} + +fn main() { + test_1::check(); + test_2::check(); + test_3::check(); +} diff --git a/tests/incremental/delegation/mapping/inherent-impl-to-trait-pass.rs b/tests/incremental/delegation/mapping/inherent-impl-to-trait-pass.rs new file mode 100644 index 0000000000000..db0d21480500a --- /dev/null +++ b/tests/incremental/delegation/mapping/inherent-impl-to-trait-pass.rs @@ -0,0 +1,233 @@ +//@ run-pass +//@ revisions:rpass1 rpass2 + +#![feature(fn_delegation)] +#![allow(incomplete_features)] +#![allow(late_bound_lifetime_arguments)] + +//! This is one of the mapping tests, which tests mapping of delegee parent and child +//! generic params, whose main goal is to create cases with +//! different number of lifetimes/types/consts in delegee child and parent; and in +//! delegation parent if applicable. At some tests predicates are +//! added. At some tests user-specified args are specified in reuse statement. + +// Testing types in parent, none in child, +// user-specified args in parent, checking predicates inheritance, +// with additional generic params in delegation parent, with impl traits +mod test_1 { + trait Trait { + fn foo(&self, _f: impl FnOnce(T) -> String) {} + } + + struct F; + impl Trait for F {} + + #[allow(dead_code)] // Fields are used instead of phantom data for generics use + struct S<'a, 'b, 'c, A, B>(F, &'a A, &'b B, &'c B); + impl<'a, 'b, 'c, A, B> S<'a, 'b, 'c, A, B> { + reuse Trait::::foo { &self.0 } + } + + pub fn check() { + let s = S(F, &123, &123, &123); + S::<'static, 'static, 'static, i32, i32>::foo(&s, |t| t.to_string()); + s.foo(|t| t.to_string()); + } +} + +// Testing lifetimes + types/consts in parent, none in child, +// with additional generic params in delegation parent +mod test_2 { + trait Trait<'x, 'y, T, const B: bool> { + fn foo(&self) {} + } + + struct F; + impl<'x, 'y, T, const B: bool> Trait<'x, 'y, T, B> for F {} + + #[allow(dead_code)] // Fields are used instead of phantom data for generics use + struct S<'a, 'b, 'c, A, B>(F, &'a A, &'b B, &'c B); + impl<'a, 'b, 'c, A, B> S<'a, 'b, 'c, A, B> { + reuse Trait::<'a, 'b, String, true>::foo { &self.0 } + } + + pub fn check() { + let s = S(F, &123, &123, &123); + S::<'static, 'static, 'static, i32, i32>::foo(&s); + s.foo(); + } +} + +// Testing lifetimes in parent, none in child, +// with additional generic params in delegation parent +mod test_3 { + trait Trait<'x, 'y> { + fn foo(&self) {} + } + + struct F; + impl<'x, 'y> Trait<'x, 'y> for F {} + + #[allow(dead_code)] // Fields are used instead of phantom data for generics use + struct S<'a, 'b, 'c, A, B>(F, &'a A, &'b B, &'c B); + impl<'a, 'b, 'c, A, B> S<'a, 'b, 'c, A, B> { + reuse Trait::<'a, 'b>::foo { &self.0 } + } + + pub fn check() { + let s = S(F, &123, &123, &123); + S::<'static, 'static, 'static, i32, i32>::foo(&s); + s.foo(); + } +} + +// Testing none in parent, none in child, +// with additional generic params in delegation parent +mod test_4 { + trait Trait { + fn foo(&self) {} + } + + struct F; + impl Trait for F {} + + #[allow(dead_code)] // Fields are used instead of phantom data for generics use + struct S<'a, 'b, 'c, A, B>(F, &'a A, &'b B, &'c B); + impl<'a, 'b, 'c, A, B> S<'a, 'b, 'c, A, B> { + reuse Trait::foo { &self.0 } + } + + pub fn check() { + let s = S(F, &123, &123, &123); + S::<'static, 'static, 'static, i32, i32>::foo(&s); + s.foo(); + } +} + +// Testing none in parent, lifetimes in child, +// with additional generic params in delegation parent +mod test_5 { + trait Trait { + fn foo<'a: 'a, 'b: 'b>(&self) {} + } + + struct F; + impl Trait for F {} + + #[allow(dead_code)] // Fields are used instead of phantom data for generics use + struct S<'a, 'b, 'c, A, B>(F, &'a A, &'b B, &'c B); + impl<'a, 'b, 'c, A, B> S<'a, 'b, 'c, A, B> { + reuse Trait::foo::<'a, 'b> { &self.0 } + } + + pub fn check() { + let s = S(F, &123, &123, &123); + S::<'static, 'static, 'static, i32, i32>::foo(&s); + s.foo(); + } +} + +// Testing none in parent, lifetimes + types in child, +// with additional generic params in delegation parent +mod test_6 { + trait Trait { + fn foo<'a: 'a, 'b: 'b, A, B, C>(&self) {} + } + + struct F; + impl Trait for F {} + + #[allow(dead_code)] // Fields are used instead of phantom data for generics use + struct S<'a, 'b, 'c, A, B>(F, &'a A, &'b B, &'c B); + impl<'a, 'b, 'c, A, B> S<'a, 'b, 'c, A, B> { + reuse Trait::foo::<'a, 'b, A, B, String> { &self.0 } + } + + pub fn check() { + let s = S(F, &123, &123, &123); + S::<'static, 'static, 'static, i32, i32>::foo(&s); + s.foo(); + } +} + +// Testing lifetimes in parent, lifetimes + types in child, +// with additional generic params in delegation parent +mod test_7 { + trait Trait<'x, 'y, 'z> { + fn foo<'a: 'a, 'b: 'b, A, B, C>(&self) {} + } + + struct F; + impl<'a, 'b, 'c> Trait<'a, 'b, 'c> for F {} + + #[allow(dead_code)] // Fields are used instead of phantom data for generics use + struct S<'a, 'b, 'c, A, B>(F, &'a A, &'b B, &'c B); + impl<'a, 'b, 'c, A, B> S<'a, 'b, 'c, A, B> { + reuse Trait::<'a, 'b, 'c>::foo::<'a, 'b, A, B, String> { &self.0 } + } + + pub fn check() { + let s = S(F, &123, &123, &123); + S::<'static, 'static, 'static, i32, i32>::foo(&s); + s.foo(); + } +} + +// Testing lifetimes + types in parent, lifetimes + types in child, +// with additional generic params in delegation parent +mod test_8 { + trait Trait<'x, 'y, 'z, X, Y, Z> { + fn foo<'a: 'a, 'b: 'b, A, B, C>(&self) {} + } + + struct F; + impl<'a, 'b, 'c, X, Y, Z> Trait<'a, 'b, 'c, X, Y, Z> for F {} + + #[allow(dead_code)] // Fields are used instead of phantom data for generics use + struct S<'a, 'b, 'c, A, B>(F, &'a A, &'b B, &'c B); + impl<'a, 'b, 'c, A, B> S<'a, 'b, 'c, A, B> { + reuse Trait::<'a, 'b, 'c, B, A, i32>::foo::<'a, 'b, A, B, String> { &self.0 } + } + + pub fn check() { + let s = S(F, &123, &123, &123); + S::<'static, 'static, 'static, i32, i32>::foo(&s); + s.foo(); + } +} + +// Testing lifetimes + types in parent, lifetimes + types in child, +// with additional generic params in delegation parent, +// inside a function with generic params +mod test_9 { + trait Trait<'x, 'y, 'z, X, Y, Z> { + fn foo<'a: 'a, 'b: 'b, A, B, C>(&self) {} + } + + struct F; + impl<'a, 'b, 'c, X, Y, Z> Trait<'a, 'b, 'c, X, Y, Z> for F {} + + pub fn check() { + #[allow(dead_code)] // Fields are used instead of phantom data for generics use + struct S<'a, 'b, 'c, A, B>(F, &'a A, &'b B, &'c B); + impl<'a, 'b, 'c, A, B> S<'a, 'b, 'c, A, B> { + reuse Trait::<'a, 'b, 'c, B, A, i32>::foo::<'a, 'b, A, B, String> { &self.0 } + } + + let s = S(F, &123, &123, &123); + S::<'static, 'static, 'static, i32, i32>::foo(&s); + s.foo(); + } +} + +pub fn main() { + test_1::check(); + test_2::check(); + test_3::check(); + test_4::check(); + test_5::check(); + test_6::check(); + test_7::check(); + test_8::check(); + test_9::check::(); +} diff --git a/tests/incremental/delegation/mapping/trait-to-free-pass.rs b/tests/incremental/delegation/mapping/trait-to-free-pass.rs new file mode 100644 index 0000000000000..fd6fe0277373b --- /dev/null +++ b/tests/incremental/delegation/mapping/trait-to-free-pass.rs @@ -0,0 +1,137 @@ +//@ run-pass +//@ revisions:rpass1 rpass2 + +#![feature(fn_delegation)] +#![allow(incomplete_features)] + +//! This is one of the mapping tests, which tests mapping of delegee parent and child +//! generic params, whose main goal is to create cases with +//! different number of lifetimes/types/consts in delegee child and parent; and in +//! delegation parent if applicable. At some tests predicates are +//! added. At some tests user-specified args are specified in reuse statement. + +// Testing lifetimes + types/consts in child, lifetimes + types/consts in delegation parent, +// with(out) user-specified args, with impl traits +mod test_1 { + fn foo<'a: 'a, 'b: 'b, T: Clone + ToString, U: Clone, const N: usize>( + _f: impl FnOnce(T) -> (T, U)) {} + + trait Trait<'a, A, B, C, const N: usize> { + reuse foo; + reuse foo::<'static, 'static, i32, String, 1> as bar; + } + + impl Trait<'static, i32, i32, i32, 1> for u32 {} + pub fn check() { + > + ::foo::<'static, 'static, i32, String, 1>(|t| (t, "".to_string())); + >::bar(|t| (t, t.to_string())); + u32::bar(|t| (t, t.to_string())); + } +} + +// Testing types/consts in child, lifetimes + types/consts in delegation parent, +// with(out) user-specified args +mod test_2 { + fn foo() {} + + trait Trait<'a, A, B, C, const N: usize> { + reuse foo; + reuse foo:: as bar; + } + + impl Trait<'static, i32, i32, i32, 1> for u32 {} + pub fn check() { + >::foo::(); + >::bar(); + } +} + +// Testing none in child, lifetimes + types/consts in delegation parent, +// with(out) user-specified args +mod test_3 { + fn foo() {} + + trait Trait<'a, A, B, C, const N: usize> { + reuse foo; + } + + impl Trait<'static, i32, i32, i32, 1> for u32 {} + pub fn check() { + >::foo(); + } +} + +// Testing lifetimes + types/consts in child, types/consts in delegation parent, +// with(out) user-specified args +mod test_4 { + fn foo<'a: 'a, 'b: 'b, T: Clone, U: Clone, const N: usize>() {} + + trait Trait { + reuse foo; + reuse foo::<'static, 'static, i32, String, 1> as bar; + } + + impl Trait for u32 {} + pub fn check() { + >::foo::<'static, 'static, i32, String, 1>(); + >::bar(); + } +} + +// Testing lifetimes + types/consts in child, none in delegation parent, +// with(out) user-specified args +mod test_5 { + fn foo<'a: 'a, 'b: 'b, T: Clone, U: Clone, const N: usize>() {} + + trait Trait { + reuse foo; + reuse foo::<'static, 'static, i32, String, 1> as bar; + } + + impl Trait for u32 {} + pub fn check() { + ::foo::<'static, 'static, i32, String, 1>(); + ::bar(); + } +} + +// Testing types/consts in child, none in delegation parent, with(out) user-specified args +mod test_6 { + fn foo() {} + + trait Trait { + reuse foo; + reuse foo:: as bar; + } + + impl Trait for u32 {} + pub fn check() { + ::foo::(); + ::bar(); + } +} + +// Testing none in child, none in delegation parent, with(out) user-specified args +mod test_7 { + fn foo() {} + + trait Trait { + reuse foo; + } + + impl Trait for u32 {} + pub fn check() { + ::foo(); + } +} + +pub fn main() { + test_1::check(); + test_2::check(); + test_3::check(); + test_4::check(); + test_5::check(); + test_6::check(); + test_7::check(); +} diff --git a/tests/incremental/delegation/mapping/trait-to-trait-pass.rs b/tests/incremental/delegation/mapping/trait-to-trait-pass.rs new file mode 100644 index 0000000000000..8b2cc711cde96 --- /dev/null +++ b/tests/incremental/delegation/mapping/trait-to-trait-pass.rs @@ -0,0 +1,799 @@ +//@ run-pass +//@ revisions:rpass1 rpass2 + +#![feature(fn_delegation)] +#![allow(incomplete_features)] +#![allow(late_bound_lifetime_arguments)] + +//! This is one of the mapping tests, which tests mapping of delegee parent and child +//! generic params, whose main goal is to create cases with +//! different number of lifetimes/types/consts in delegee child and parent; and in +//! delegation parent if applicable. At some tests predicates are +//! added. At some tests user-specified args are specified in reuse statement. + +// Testing lifetimes + types in parent, +// lifetimes + types/consts in child, +// in delegation parent with: +// lifetimes + types OR none OR lifetimes OR types, +// with(out) user-specified args, with different target expr, with impl traits +mod test_1 { + trait Trait<'b, 'c, 'a, T>: Sized { + fn foo<'d: 'd, U, const M: bool>(&self, _f: impl FnOnce(T) -> U) {} + } + + impl<'b, 'c, 'a, T> Trait<'b, 'c, 'a, T> for u8 {} + + trait Trait2<'a, 'b, 'c, X, Y, Z> { + fn get() -> &'static u8 { &0 } + fn get_self(&self) -> &'static u8 { &0 } + reuse Trait::<'static, 'static, 'static, i32>::foo as bar1 { Self::get() } + reuse Trait::<'static, 'static, 'static, i32>::foo::<'static, String, false> as bar2 { + Self::get() + } + + reuse Trait::<'static, 'static, 'static, i32>::foo as bar3 { self.get_self() } + reuse Trait::<'static, 'static, 'static, i32>::foo::<'static, String, false> + as bar4 { self.get_self() } + + // FIXME(fn_delegation): Uncomment those tests when proper support for + // generics when method call is generated is added + + // reuse Trait::foo::<'static, String, false> as bar5 { Self::get() } + // reuse Trait::foo as bar6 { Self::get() } + // reuse Trait::foo::<'static, String, false> as bar7 { self.get_self() } + // reuse Trait::foo as bar8 { self.get_self() } + } + + trait Trait3 { + fn get() -> &'static u8 { &0 } + fn get_self(&self) -> &'static u8 { &0 } + reuse Trait::<'static, 'static, 'static, i32>::foo as bar1 { Self::get() } + reuse Trait::<'static, 'static, 'static, i32>::foo::<'static, String, false> + as bar2 { Self::get() } + reuse Trait::<'static, 'static, 'static, i32>::foo as bar3 { self.get_self() } + reuse Trait::<'static, 'static, 'static, i32>::foo::<'static, String, false> + as bar4 { self.get_self() } + } + + trait Trait4<'a, 'b, 'c> { + fn get() -> &'static u8 { &0 } + fn get_self(&self) -> &'static u8 { &0 } + reuse Trait::<'static, 'static, 'static, i32>::foo as bar1 { Self::get() } + reuse Trait::<'static, 'static, 'static, i32>::foo::<'static, String, false> + as bar2 { Self::get() } + reuse Trait::<'static, 'static, 'static, i32>::foo as bar3 { self.get_self() } + reuse Trait::<'static, 'static, 'static, i32>::foo::<'static, String, false> + as bar4 { self.get_self() } + } + + trait Trait5 { + fn get() -> &'static u8 { &0 } + fn get_self(&self) -> &'static u8 { &0 } + reuse Trait::<'static, 'static, 'static, i32>::foo as bar1 { Self::get() } + reuse Trait::<'static, 'static, 'static, i32>::foo::<'static, String, false> + as bar2 { Self::get() } + reuse Trait::<'static, 'static, 'static, i32>::foo as bar3 { self.get_self() } + reuse Trait::<'static, 'static, 'static, i32>::foo::<'static, String, false> + as bar4 { self.get_self() } + } + + impl<'a, 'b, 'c, X, Y, Z> Trait2<'a, 'b, 'c, X, Y, Z> for u32 {} + impl Trait3 for u32 {} + impl<'a, 'b, 'c> Trait4<'a, 'b, 'c> for u32 {} + impl Trait5 for u32 {} + + pub fn check<'a: 'a>() { + > + ::bar1::<'static, String, true>(&123, |x| x.to_string()); + ::bar1::<'static, String, true>(&123, |x| x.to_string()); + >::bar1::<'static, String, true>(&123, |x| x.to_string()); + >::bar1::<'static, String, true>(&123, |x| x.to_string()); + + >::bar2(&123, |x| x.to_string()); + ::bar2(&123, |x| x.to_string()); + >::bar2(&123, |x| x.to_string()); + >::bar2(&123, |x| x.to_string()); + + > + ::bar3::<'static, String, true>(&123, |x| x.to_string()); + ::bar3::<'static, String, true>(&123, |x| x.to_string()); + >::bar3::<'static, String, true>(&123, |x| x.to_string()); + >::bar3::<'static, String, true>(&123, |x| x.to_string()); + + >::bar4(&123, |x| x.to_string()); + ::bar4(&123, |x| x.to_string()); + >::bar4(&123, |x| x.to_string()); + >::bar4(&123, |x| x.to_string()); + } +} + +// Testing types in parent, +// lifetimes + types/consts in child, +// in delegation parent with: +// lifetimes + types OR none OR lifetimes OR types, +// with(out) user-specified args, with different target expr +mod test_2 { + trait Trait: Sized { + fn foo<'d: 'd, U, const M: bool>(&self) {} + } + + impl Trait for u8 {} + + trait Trait2<'a, 'b, 'c, X, Y, Z> { + fn get() -> &'static u8 { &0 } + fn get_self(&self) -> &'static u8 { &0 } + reuse Trait::::foo as bar1 { Self::get() } + reuse Trait::::foo::<'static, String, false> as bar2 { Self::get() } + reuse Trait::::foo as bar3 { self.get_self() } + reuse Trait::::foo::<'static, String, false> as bar4 { self.get_self() } + } + + trait Trait3 { + fn get() -> &'static u8 { &0 } + fn get_self(&self) -> &'static u8 { &0 } + reuse Trait::::foo as bar1 { Self::get() } + reuse Trait::::foo::<'static, String, false> as bar2 { Self::get() } + reuse Trait::::foo as bar3 { self.get_self() } + reuse Trait::::foo::<'static, String, false> as bar4 { self.get_self() } + } + + trait Trait4<'a, 'b, 'c> { + fn get() -> &'static u8 { &0 } + fn get_self(&self) -> &'static u8 { &0 } + reuse Trait::::foo as bar1 { Self::get() } + reuse Trait::::foo::<'static, String, false> as bar2 { Self::get() } + reuse Trait::::foo as bar3 { self.get_self() } + reuse Trait::::foo::<'static, String, false> as bar4 { self.get_self() } + } + + trait Trait5 { + fn get() -> &'static u8 { &0 } + fn get_self(&self) -> &'static u8 { &0 } + reuse Trait::::foo as bar1 { Self::get() } + reuse Trait::::foo::<'static, String, false> as bar2 { Self::get() } + reuse Trait::::foo as bar3 { self.get_self() } + reuse Trait::::foo::<'static, String, false> as bar4 { self.get_self() } + } + + impl<'a, 'b, 'c, X, Y, Z> Trait2<'a, 'b, 'c, X, Y, Z> for u32 {} + impl Trait3 for u32 {} + impl<'a, 'b, 'c> Trait4<'a, 'b, 'c> for u32 {} + impl Trait5 for u32 {} + + pub fn check<'a: 'a>() { + > + ::bar1::<'static, String, true>(&123); + ::bar1::<'static, String, true>(&123); + >::bar1::<'static, String, true>(&123); + >::bar1::<'static, String, true>(&123); + + >::bar2(&123); + ::bar2(&123); + >::bar2(&123); + >::bar2(&123); + + > + ::bar3::<'static, String, true>(&123); + ::bar3::<'static, String, true>(&123); + >::bar3::<'static, String, true>(&123); + >::bar3::<'static, String, true>(&123); + + >::bar4(&123); + ::bar4(&123); + >::bar4(&123); + >::bar4(&123); + } +} + +// Testing lifetimes in parent, +// lifetimes + types/consts in child, +// in delegation parent with: +// lifetimes + types OR none OR lifetimes OR types, +// with(out) user-specified args, with different target expr +mod test_3 { + trait Trait<'b, 'c, 'a>: Sized { + fn foo<'d: 'd, U, const M: bool>(&self) {} + } + + impl<'b, 'c, 'a> Trait<'b, 'c, 'a> for u8 {} + + trait Trait2<'a, 'b, 'c, X, Y, Z> { + fn get() -> &'static u8 { &0 } + fn get_self(&self) -> &'static u8 { &0 } + reuse Trait::<'static, 'static, 'static>::foo as bar1 { Self::get() } + reuse Trait::<'static, 'static, 'static>::foo::<'static, String, false> as bar2 { + Self::get() + } + reuse Trait::<'static, 'static, 'static>::foo as bar3 { self.get_self() } + reuse Trait::<'static, 'static, 'static>::foo::<'static, String, false> as bar4 { + self.get_self() + } + } + + trait Trait3 { + fn get() -> &'static u8 { &0 } + fn get_self(&self) -> &'static u8 { &0 } + reuse Trait::<'static, 'static, 'static>::foo as bar1 { Self::get() } + reuse Trait::<'static, 'static, 'static>::foo::<'static, String, false> as bar2 { + Self::get() + } + reuse Trait::<'static, 'static, 'static>::foo as bar3 { self.get_self() } + reuse Trait::<'static, 'static, 'static>::foo::<'static, String, false> as bar4 { + self.get_self() + } + } + + trait Trait4<'a, 'b, 'c> { + fn get() -> &'static u8 { &0 } + fn get_self(&self) -> &'static u8 { &0 } + reuse Trait::<'static, 'static, 'static>::foo as bar1 { Self::get() } + reuse Trait::<'static, 'static, 'static>::foo::<'static, String, false> as bar2 { + Self::get() + } + reuse Trait::<'static, 'static, 'static>::foo as bar3 { self.get_self() } + reuse Trait::<'static, 'static, 'static>::foo::<'static, String, false> as bar4 { + self.get_self() + } + } + + trait Trait5 { + fn get() -> &'static u8 { &0 } + fn get_self(&self) -> &'static u8 { &0 } + reuse Trait::<'static, 'static, 'static>::foo as bar1 { Self::get() } + reuse Trait::<'static, 'static, 'static>::foo::<'static, String, false> + as bar2 { Self::get() } + reuse Trait::<'static, 'static, 'static>::foo as bar3 { self.get_self() } + reuse Trait::<'static, 'static, 'static>::foo::<'static, String, false> + as bar4 { self.get_self() } + } + + impl<'a, 'b, 'c, X, Y, Z> Trait2<'a, 'b, 'c, X, Y, Z> for u32 {} + impl Trait3 for u32 {} + impl<'a, 'b, 'c> Trait4<'a, 'b, 'c> for u32 {} + impl Trait5 for u32 {} + + pub fn check<'a: 'a>() { + > + ::bar1::<'static, String, true>(&123); + ::bar1::<'static, String, true>(&123); + >::bar1::<'static, String, true>(&123); + >::bar1::<'static, String, true>(&123); + + >::bar2(&123); + ::bar2(&123); + >::bar2(&123); + >::bar2(&123); + + > + ::bar3::<'static, String, true>(&123); + ::bar3::<'static, String, true>(&123); + >::bar3::<'static, String, true>(&123); + >::bar3::<'static, String, true>(&123); + + >::bar4(&123); + ::bar4(&123); + >::bar4(&123); + >::bar4(&123); + } +} + +// Testing none in parent, +// lifetimes + types/consts in child, +// in delegation parent with: +// lifetimes + types OR none OR lifetimes OR types, +// with(out) user-specified args, with different target expr +mod test_4 { + trait Trait: Sized { + fn foo<'d: 'd, U, const M: bool>(&self) {} + } + + impl Trait for u8 {} + + trait Trait2<'a, 'b, 'c, X, Y, Z> { + fn get() -> &'static u8 { &0 } + fn get_self(&self) -> &'static u8 { &0 } + reuse Trait::foo as bar1 { Self::get() } + reuse Trait::foo::<'static, String, false> as bar2 { Self::get() } + reuse Trait::foo as bar3 { self.get_self() } + reuse Trait::foo::<'static, String, false> as bar4 { self.get_self() } + } + + trait Trait3 { + fn get() -> &'static u8 { &0 } + fn get_self(&self) -> &'static u8 { &0 } + reuse Trait::foo as bar1 { Self::get() } + reuse Trait::foo::<'static, String, false> as bar2 { Self::get() } + reuse Trait::foo as bar3 { self.get_self() } + reuse Trait::foo::<'static, String, false> as bar4 { self.get_self() } + } + + trait Trait4<'a, 'b, 'c> { + fn get() -> &'static u8 { &0 } + fn get_self(&self) -> &'static u8 { &0 } + reuse Trait::foo as bar1 { Self::get() } + reuse Trait::foo::<'static, String, false> as bar2 { Self::get() } + reuse Trait::foo as bar3 { self.get_self() } + reuse Trait::foo::<'static, String, false> as bar4 { self.get_self() } + } + + trait Trait5 { + fn get() -> &'static u8 { &0 } + fn get_self(&self) -> &'static u8 { &0 } + reuse Trait::foo as bar1 { Self::get() } + reuse Trait::foo::<'static, String, false> as bar2 { Self::get() } + reuse Trait::foo as bar3 { self.get_self() } + reuse Trait::foo::<'static, String, false> as bar4 { self.get_self() } + } + + impl<'a, 'b, 'c, X, Y, Z> Trait2<'a, 'b, 'c, X, Y, Z> for u32 {} + impl Trait3 for u32 {} + impl<'a, 'b, 'c> Trait4<'a, 'b, 'c> for u32 {} + impl Trait5 for u32 {} + + pub fn check<'a: 'a>() { + > + ::bar1::<'static, String, true>(&123); + ::bar1::<'static, String, true>(&123); + >::bar1::<'static, String, true>(&123); + >::bar1::<'static, String, true>(&123); + + >::bar2(&123); + ::bar2(&123); + >::bar2(&123); + >::bar2(&123); + + > + ::bar3::<'static, String, true>(&123); + ::bar3::<'static, String, true>(&123); + >::bar3::<'static, String, true>(&123); + >::bar3::<'static, String, true>(&123); + + >::bar4(&123); + ::bar4(&123); + >::bar4(&123); + >::bar4(&123); + } +} + +// Testing lifetimes + types in parent, +// types/consts in child, +// in delegation parent with: +// lifetimes + types OR none OR lifetimes OR types, +// with(out) user-specified args, with different target expr +mod test_5 { + trait Trait<'b, 'c, 'a, T>: Sized { + fn foo(&self) {} + } + + impl<'b, 'c, 'a, T> Trait<'b, 'c, 'a, T> for u8 {} + + trait Trait2<'a, 'b, 'c, X, Y, Z> { + fn get() -> &'static u8 { &0 } + fn get_self(&self) -> &'static u8 { &0 } + reuse Trait::<'static, 'static, 'static, i32>::foo as bar1 { Self::get() } + reuse Trait::<'static, 'static, 'static, i32>::foo:: as bar2 { + Self::get() + } + reuse Trait::<'static, 'static, 'static, i32>::foo as bar3 { self.get_self() } + reuse Trait::<'static, 'static, 'static, i32>::foo:: as bar4 { + self.get_self() + } + } + + trait Trait3 { + fn get() -> &'static u8 { &0 } + fn get_self(&self) -> &'static u8 { &0 } + reuse Trait::<'static, 'static, 'static, i32>::foo as bar1 { Self::get() } + reuse Trait::<'static, 'static, 'static, i32>::foo:: as bar2 { + Self::get() + } + reuse Trait::<'static, 'static, 'static, i32>::foo as bar3 { self.get_self() } + reuse Trait::<'static, 'static, 'static, i32>::foo:: as bar4 { + self.get_self() + } + } + + trait Trait4<'a, 'b, 'c> { + fn get() -> &'static u8 { &0 } + fn get_self(&self) -> &'static u8 { &0 } + reuse Trait::<'static, 'static, 'static, i32>::foo as bar1 { Self::get() } + reuse Trait::<'static, 'static, 'static, i32>::foo:: as bar2 { + Self::get() + } + reuse Trait::<'static, 'static, 'static, i32>::foo as bar3 { self.get_self() } + reuse Trait::<'static, 'static, 'static, i32>::foo:: as bar4 { + self.get_self() + } + } + + trait Trait5 { + fn get() -> &'static u8 { &0 } + fn get_self(&self) -> &'static u8 { &0 } + reuse Trait::<'static, 'static, 'static, i32>::foo as bar1 { Self::get() } + reuse Trait::<'static, 'static, 'static, i32>::foo:: as bar2 { + Self::get() + } + reuse Trait::<'static, 'static, 'static, i32>::foo as bar3 { self.get_self() } + reuse Trait::<'static, 'static, 'static, i32>::foo:: as bar4 { + self.get_self() + } + } + + impl<'a, 'b, 'c, X, Y, Z> Trait2<'a, 'b, 'c, X, Y, Z> for u32 {} + impl Trait3 for u32 {} + impl<'a, 'b, 'c> Trait4<'a, 'b, 'c> for u32 {} + impl Trait5 for u32 {} + + pub fn check<'a: 'a>() { + >::bar1::(&123); + ::bar1::(&123); + >::bar1::(&123); + >::bar1::(&123); + + >::bar2(&123); + ::bar2(&123); + >::bar2(&123); + >::bar2(&123); + + >::bar3::(&123); + ::bar3::(&123); + >::bar3::(&123); + >::bar3::(&123); + + >::bar4(&123); + ::bar4(&123); + >::bar4(&123); + >::bar4(&123); + } +} + +// Testing lifetimes + types in parent, +// none in child, +// in delegation parent with: +// lifetimes + types OR none OR lifetimes OR types, +// with(out) user-specified args, with different target expr +mod test_6 { + trait Trait<'b, 'c, 'a, T>: Sized { + fn foo(&self) {} + } + + impl<'b, 'c, 'a, T> Trait<'b, 'c, 'a, T> for u8 {} + + trait Trait2<'a, 'b, 'c, X, Y, Z> { + fn get() -> &'static u8 { &0 } + fn get_self(&self) -> &'static u8 { &0 } + reuse Trait::<'static, 'static, 'static, i32>::foo as bar1 { Self::get() } + reuse Trait::<'static, 'static, 'static, i32>::foo as bar3 { self.get_self() } + } + + trait Trait3 { + fn get() -> &'static u8 { &0 } + fn get_self(&self) -> &'static u8 { &0 } + reuse Trait::<'static, 'static, 'static, i32>::foo as bar1 { Self::get() } + reuse Trait::<'static, 'static, 'static, i32>::foo as bar3 { self.get_self() } + } + + trait Trait4<'a, 'b, 'c> { + fn get() -> &'static u8 { &0 } + fn get_self(&self) -> &'static u8 { &0 } + reuse Trait::<'static, 'static, 'static, i32>::foo as bar1 { Self::get() } + reuse Trait::<'static, 'static, 'static, i32>::foo as bar3 { self.get_self() } + } + + trait Trait5 { + fn get() -> &'static u8 { &0 } + fn get_self(&self) -> &'static u8 { &0 } + reuse Trait::<'static, 'static, 'static, i32>::foo as bar1 { Self::get() } + reuse Trait::<'static, 'static, 'static, i32>::foo as bar3 { self.get_self() } + } + + impl<'a, 'b, 'c, X, Y, Z> Trait2<'a, 'b, 'c, X, Y, Z> for u32 {} + impl Trait3 for u32 {} + impl<'a, 'b, 'c> Trait4<'a, 'b, 'c> for u32 {} + impl Trait5 for u32 {} + + pub fn check<'a: 'a>() { + >::bar1(&123); + ::bar1(&123); + >::bar1(&123); + >::bar1(&123); + + >::bar3(&123); + ::bar3(&123); + >::bar3(&123); + >::bar3(&123); + } +} + +// Testing types in parent, +// none in child, +// in delegation parent with: +// lifetimes + types OR none OR lifetimes OR types, +// with user-specified args, with different target expr +mod test_7 { + trait Trait: Sized { + fn foo(&self) {} + } + + impl Trait for u8 {} + + trait Trait2<'a, 'b, 'c, X, Y, Z> { + fn get() -> &'static u8 { &0 } + fn get_self(&self) -> &'static u8 { &0 } + reuse Trait::::foo as bar1 { Self::get() } + reuse Trait::::foo as bar3 { self.get_self() } + } + + trait Trait3 { + fn get() -> &'static u8 { &0 } + fn get_self(&self) -> &'static u8 { &0 } + reuse Trait::::foo as bar1 { Self::get() } + reuse Trait::::foo as bar3 { self.get_self() } + } + + trait Trait4<'a, 'b, 'c> { + fn get() -> &'static u8 { &0 } + fn get_self(&self) -> &'static u8 { &0 } + reuse Trait::::foo as bar1 { Self::get() } + reuse Trait::::foo as bar3 { self.get_self() } + } + + trait Trait5 { + fn get() -> &'static u8 { &0 } + fn get_self(&self) -> &'static u8 { &0 } + reuse Trait::::foo as bar1 { Self::get() } + reuse Trait::::foo as bar3 { self.get_self() } + } + + impl<'a, 'b, 'c, X, Y, Z> Trait2<'a, 'b, 'c, X, Y, Z> for u32 {} + impl Trait3 for u32 {} + impl<'a, 'b, 'c> Trait4<'a, 'b, 'c> for u32 {} + impl Trait5 for u32 {} + + pub fn check<'a: 'a>() { + >::bar1(&123); + ::bar1(&123); + >::bar1(&123); + >::bar1(&123); + + >::bar3(&123); + ::bar3(&123); + >::bar3(&123); + >::bar3(&123); + } +} + +// Testing none in parent, +// none in child, +// in delegation parent with: +// lifetimes + types OR none OR lifetimes OR types, +// without user-specified args, with different target expr +mod test_8 { + trait Trait: Sized { + fn foo(&self) {} + } + + impl Trait for u8 {} + + trait Trait2<'a, 'b, 'c, X, Y, Z> { + fn get() -> &'static u8 { &0 } + fn get_self(&self) -> &'static u8 { &0 } + reuse Trait::foo as bar1 { Self::get() } + reuse Trait::foo as bar3 { self.get_self() } + } + + trait Trait3 { + fn get() -> &'static u8 { &0 } + fn get_self(&self) -> &'static u8 { &0 } + reuse Trait::foo as bar1 { Self::get() } + reuse Trait::foo as bar3 { self.get_self() } + } + + trait Trait4<'a, 'b, 'c> { + fn get() -> &'static u8 { &0 } + fn get_self(&self) -> &'static u8 { &0 } + reuse Trait::foo as bar1 { Self::get() } + reuse Trait::foo as bar3 { self.get_self() } + } + + trait Trait5 { + fn get() -> &'static u8 { &0 } + fn get_self(&self) -> &'static u8 { &0 } + reuse Trait::foo as bar1 { Self::get() } + reuse Trait::foo as bar3 { self.get_self() } + } + + impl<'a, 'b, 'c, X, Y, Z> Trait2<'a, 'b, 'c, X, Y, Z> for u32 {} + impl Trait3 for u32 {} + impl<'a, 'b, 'c> Trait4<'a, 'b, 'c> for u32 {} + impl Trait5 for u32 {} + + pub fn check<'a: 'a>() { + >::bar1(&123); + ::bar1(&123); + >::bar1(&123); + >::bar1(&123); + + >::bar3(&123); + ::bar3(&123); + >::bar3(&123); + >::bar3(&123); + } +} + +// Testing types in parent, +// lifetimes in child, +// in delegation parent with: +// lifetimes + types OR none OR lifetimes OR types, +// with(out) user-specified args, with different target expr +mod test_9 { + trait Trait: Sized { + fn foo<'a: 'a, 'b: 'b>(&self) {} + } + + impl Trait for u8 {} + + trait Trait2<'a, 'b, 'c, X, Y, Z> { + fn get() -> &'static u8 { &0 } + fn get_self(&self) -> &'static u8 { &0 } + reuse Trait::::foo as bar1 { Self::get() } + reuse Trait::::foo::<'static, 'static> as bar2 { Self::get() } + reuse Trait::::foo as bar3 { self.get_self() } + reuse Trait::::foo::<'static, 'static> as bar4 { self.get_self() } + } + + trait Trait3 { + fn get() -> &'static u8 { &0 } + fn get_self(&self) -> &'static u8 { &0 } + reuse Trait::::foo as bar1 { Self::get() } + reuse Trait::::foo::<'static, 'static> as bar2 { Self::get() } + reuse Trait::::foo as bar3 { self.get_self() } + reuse Trait::::foo::<'static, 'static> as bar4 { self.get_self() } + } + + trait Trait4<'a, 'b, 'c> { + fn get() -> &'static u8 { &0 } + fn get_self(&self) -> &'static u8 { &0 } + reuse Trait::::foo as bar1 { Self::get() } + reuse Trait::::foo::<'static, 'static> as bar2 { Self::get() } + reuse Trait::::foo as bar3 { self.get_self() } + reuse Trait::::foo::<'static, 'static> as bar4 { self.get_self() } + } + + trait Trait5 { + fn get() -> &'static u8 { &0 } + fn get_self(&self) -> &'static u8 { &0 } + reuse Trait::::foo as bar1 { Self::get() } + reuse Trait::::foo::<'static, 'static> as bar2 { Self::get() } + reuse Trait::::foo as bar3 { self.get_self() } + reuse Trait::::foo::<'static, 'static> as bar4 { self.get_self() } + } + + impl<'a, 'b, 'c, X, Y, Z> Trait2<'a, 'b, 'c, X, Y, Z> for u32 {} + impl Trait3 for u32 {} + impl<'a, 'b, 'c> Trait4<'a, 'b, 'c> for u32 {} + impl Trait5 for u32 {} + + pub fn check<'a: 'a>() { + > + ::bar1::<'static, 'static>(&123); + ::bar1::<'static, 'static>(&123); + >::bar1::<'a, 'a>(&123); + >::bar1::<'a, 'a>(&123); + + >::bar2(&123); + ::bar2(&123); + >::bar2(&123); + >::bar2(&123); + + > + ::bar3::<'static, 'static>(&123); + ::bar3::<'static, 'static>(&123); + >::bar3::<'static, 'static>(&123); + >::bar3::<'static, 'static>(&123); + + >::bar4(&123); + ::bar4(&123); + >::bar4(&123); + >::bar4(&123); + } +} + +// Testing lifetimes in parent, +// lifetimes in child, +// in delegation parent with: +// lifetimes + types OR none OR lifetimes OR types, +// with(out) user-specified args, with different target expr +mod test_10 { + trait Trait<'x, 'y, 'z>: Sized { + fn foo<'a: 'a, 'b: 'b>(&self) {} + } + + impl<'x, 'y, 'z> Trait<'x, 'y, 'z> for u8 {} + + trait Trait2<'a, 'b, 'c, X, Y, Z> { + fn get() -> &'static u8 { &0 } + fn get_self(&self) -> &'static u8 { &0 } + reuse Trait::<'a, 'b, 'static>::foo as bar1 { Self::get() } + reuse Trait::<'a, 'b, 'static>::foo::<'static, 'static> as bar2 { Self::get() } + reuse Trait::<'a, 'b, 'static>::foo as bar3 { self.get_self() } + reuse Trait::<'a, 'b, 'static>::foo::<'static, 'static> as bar4 { self.get_self() } + } + + trait Trait3 { + fn get() -> &'static u8 { &0 } + fn get_self(&self) -> &'static u8 { &0 } + reuse Trait::<'static, 'static, 'static>::foo as bar1 { Self::get() } + reuse Trait::<'static, 'static, 'static>::foo::<'static, 'static> as bar2 { + Self::get() + } + reuse Trait::<'static, 'static, 'static>::foo as bar3 { self.get_self() } + reuse Trait::<'static, 'static, 'static>::foo::<'static, 'static> as bar4 { + self.get_self() + } + } + + trait Trait4<'a, 'b, 'c> { + fn get() -> &'static u8 { &0 } + fn get_self(&self) -> &'static u8 { &0 } + reuse Trait::<'a, 'b, 'static>::foo as bar1 { Self::get() } + reuse Trait::<'a, 'b, 'static>::foo::<'static, 'static> as bar2 { Self::get() } + reuse Trait::<'a, 'b, 'static>::foo as bar3 { self.get_self() } + reuse Trait::<'a, 'b, 'static>::foo::<'static, 'static> as bar4 { self.get_self() } + } + + trait Trait5 { + fn get() -> &'static u8 { &0 } + fn get_self(&self) -> &'static u8 { &0 } + reuse Trait::<'static, 'static, 'static>::foo as bar1 { Self::get() } + reuse Trait::<'static, 'static, 'static>::foo::<'static, 'static> as bar2 { + Self::get() + } + reuse Trait::<'static, 'static, 'static>::foo as bar3 { self.get_self() } + reuse Trait::<'static, 'static, 'static>::foo::<'static, 'static> as bar4 { + self.get_self() + } + } + + impl<'a, 'b, 'c, X, Y, Z> Trait2<'a, 'b, 'c, X, Y, Z> for u32 {} + impl Trait3 for u32 {} + impl<'a, 'b, 'c> Trait4<'a, 'b, 'c> for u32 {} + impl Trait5 for u32 {} + + pub fn check<'a: 'a>() { + > + ::bar1::<'static, 'static>(&123); + ::bar1::<'static, 'static>(&123); + >::bar1::<'a, 'a>(&123); + >::bar1::<'a, 'a>(&123); + + >::bar2(&123); + ::bar2(&123); + >::bar2(&123); + >::bar2(&123); + + > + ::bar3::<'static, 'static>(&123); + ::bar3::<'static, 'static>(&123); + >::bar3::<'static, 'static>(&123); + >::bar3::<'static, 'static>(&123); + + >::bar4(&123); + ::bar4(&123); + >::bar4(&123); + >::bar4(&123); + } +} + +pub fn main() { + test_1::check(); + test_2::check(); + test_3::check(); + test_4::check(); + test_5::check(); + test_6::check(); + test_7::check(); + test_8::check(); + test_9::check(); + test_10::check(); +} diff --git a/tests/incremental/delegation/method-call-priority.rs b/tests/incremental/delegation/method-call-priority.rs new file mode 100644 index 0000000000000..702d9f2004a24 --- /dev/null +++ b/tests/incremental/delegation/method-call-priority.rs @@ -0,0 +1,35 @@ +//@ run-pass +//@ revisions:rpass1 rpass2 + +#![feature(fn_delegation)] +#![allow(incomplete_features)] +#![allow(dead_code)] + +trait Trait1 { + fn foo(&self) -> i32 { 1 } +} + +trait Trait2 { + fn foo(&self) -> i32 { 2 } +} + +struct F; +impl Trait1 for F {} +impl Trait2 for F {} + +impl F { + fn foo(&self) -> i32 { 3 } +} + +struct S(F); + +impl Trait1 for S { + // Make sure that the generated `self.0.foo()` does not turn into the inherent method `F::foo` + // that has a higher priority than methods from traits. + reuse Trait1::foo { self.0 } +} + +fn main() { + let s = S(F); + assert_eq!(s.foo(), 1); +} diff --git a/tests/incremental/delegation/parse.rs b/tests/incremental/delegation/parse.rs new file mode 100644 index 0000000000000..2786309ba8ffb --- /dev/null +++ b/tests/incremental/delegation/parse.rs @@ -0,0 +1,43 @@ +//@ run-pass +//@ revisions:rpass1 rpass2 + +#![feature(decl_macro)] +#![feature(fn_delegation)] +#![allow(incomplete_features)] + +macro_rules! reuse { {} => {} } + +mod reuse { + pub fn to_unsafe(x: i32) -> i32 { x + 1 } + pub fn to_pub() {} + pub fn to_pub2() {} + + mod inner { + #[allow(non_camel_case_types)] + struct reuse { + a: i32, + b: i32, + c: i32, + } + + impl reuse { + reuse!(); + } + + fn baz() { + let (a, b, c) = (0, 0, 0); + reuse {a, b, c}; + } + } + + pub macro my_macro() {} +} + +reuse!(); +reuse::my_macro!(); + +#[inline] +pub reuse reuse::to_pub; +pub reuse crate::reuse::to_pub2; + +fn main() {} diff --git a/tests/incremental/delegation/rename.rs b/tests/incremental/delegation/rename.rs new file mode 100644 index 0000000000000..c6e74b3f623ca --- /dev/null +++ b/tests/incremental/delegation/rename.rs @@ -0,0 +1,28 @@ +//@ run-pass +//@ revisions:rpass1 rpass2 + +#![feature(fn_delegation)] +#![allow(incomplete_features)] + +mod to_reuse { + pub fn a() {} + pub fn b() {} +} + +reuse to_reuse::a as x; +reuse to_reuse::{a as y, b as z}; + +struct S; +impl S { + reuse to_reuse::a as x; + reuse to_reuse::{a as y, b as z}; +} + +fn main() { + x(); + y(); + z(); + S::x(); + S::y(); + S::z(); +} diff --git a/tests/incremental/delegation/self-coercion.rs b/tests/incremental/delegation/self-coercion.rs new file mode 100644 index 0000000000000..20348b9b511cd --- /dev/null +++ b/tests/incremental/delegation/self-coercion.rs @@ -0,0 +1,27 @@ +//@ run-pass +//@ revisions:rpass1 rpass2 + +#![feature(fn_delegation)] +#![allow(incomplete_features)] + +trait Trait : Sized { + fn by_value(self) -> i32 { 1 } + fn by_mut_ref(&mut self) -> i32 { 2 } + fn by_ref(&self) -> i32 { 3 } +} + +struct F; +impl Trait for F {} + +struct S(F); + +impl Trait for S { + reuse Trait::{by_value, by_mut_ref, by_ref} { self.0 } +} + +fn main() { + let mut s = S(F); + assert_eq!(s.by_ref(), 3); + assert_eq!(s.by_mut_ref(), 2); + assert_eq!(s.by_value(), 1); +} diff --git a/tests/ui/delegation/generics/generic-params-defaults.rs b/tests/ui/delegation/generics/generic-params-defaults.rs index 66a9195551337..61f844dfae639 100644 --- a/tests/ui/delegation/generics/generic-params-defaults.rs +++ b/tests/ui/delegation/generics/generic-params-defaults.rs @@ -1,3 +1,5 @@ +//@ compile-flags: -Z deduplicate-diagnostics=yes + #![feature(fn_delegation)] #![allow(incomplete_features)] diff --git a/tests/ui/delegation/generics/generic-params-defaults.stderr b/tests/ui/delegation/generics/generic-params-defaults.stderr index 76fc3fde4753c..2aba6c0bf6f46 100644 --- a/tests/ui/delegation/generics/generic-params-defaults.stderr +++ b/tests/ui/delegation/generics/generic-params-defaults.stderr @@ -1,5 +1,5 @@ error: defaults for generic parameters are not allowed here - --> $DIR/generic-params-defaults.rs:5:12 + --> $DIR/generic-params-defaults.rs:7:12 | LL | fn foo(&self) { | ^^^^^^^^^ @@ -12,7 +12,18 @@ error: aborting due to 1 previous error Future incompatibility report: Future breakage diagnostic: error: defaults for generic parameters are not allowed here - --> $DIR/generic-params-defaults.rs:5:12 + --> $DIR/generic-params-defaults.rs:7:12 + | +LL | fn foo(&self) { + | ^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #36887 + = note: `#[deny(invalid_type_param_default)]` (part of `#[deny(future_incompatible)]`) on by default + +Future breakage diagnostic: +error: defaults for generic parameters are not allowed here + --> $DIR/generic-params-defaults.rs:7:12 | LL | fn foo(&self) { | ^^^^^^^^^ diff --git a/tests/ui/delegation/query-cycle-oom.rs b/tests/ui/delegation/query-cycle-oom.rs new file mode 100644 index 0000000000000..c6c8ec5be7984 --- /dev/null +++ b/tests/ui/delegation/query-cycle-oom.rs @@ -0,0 +1,65 @@ +//@ compile-flags: -Z deduplicate-diagnostics=yes + +#![feature(fn_delegation)] +#![allow(incomplete_features)] + +mod test_1 { + trait Trait { + fn foo(&self, x: T) -> S { x } + //~^ ERROR: missing generics for struct `test_1::S` + } + struct F; + + struct S(F, T); + + impl Trait for S { + reuse to_reuse::foo { &self.0 } + //~^ ERROR: cannot find module or crate `to_reuse` in this scope + } +} + +mod test_2 { + trait Trait { + fn foo() -> Self::Assoc; + //~^ ERROR: associated type `Assoc` not found for `Self` + fn bar(&self) -> u8; + } + + impl Trait for u8 { + //~^ ERROR: not all trait items implemented, missing: `foo` + fn bar(&self) -> u8 { 1 } + } + + struct S(u8); + + impl Trait for S { + reuse Trait::* { &self.0 } + //~^ ERROR: this function takes 0 arguments but 1 argument was supplied + fn bar(&self) -> u8 { 2 } + } +} + +mod test_3 { + trait Trait { + fn foo(&self) -> Self::Assoc<3> { //~ ERROR: associated type `Assoc` not found for `Self` + [(); 3] + } + } + + impl () { //~ ERROR: cannot define inherent `impl` for primitive types + reuse Trait::*; + //~^ ERROR: no method named `foo` found for reference `&()` in the current scope + } +} + +mod test_4 { + trait Trait { + fn foo(&self, _: dyn Trait) {} + //~^ ERROR: missing generics for trait `test_4::Trait` + } + + reuse Trait::<_>::foo:: as x; + //~^ ERROR: the placeholder `_` is not allowed within types on item signatures for functions +} + +fn main() {} diff --git a/tests/ui/delegation/query-cycle-oom.stderr b/tests/ui/delegation/query-cycle-oom.stderr new file mode 100644 index 0000000000000..1104a6e404b26 --- /dev/null +++ b/tests/ui/delegation/query-cycle-oom.stderr @@ -0,0 +1,109 @@ +error[E0107]: missing generics for struct `test_1::S` + --> $DIR/query-cycle-oom.rs:8:32 + | +LL | fn foo(&self, x: T) -> S { x } + | ^ expected 1 generic argument + | +note: struct defined here, with 1 generic parameter: `T` + --> $DIR/query-cycle-oom.rs:13:12 + | +LL | struct S(F, T); + | ^ - +help: add missing generic argument + | +LL | fn foo(&self, x: T) -> S { x } + | +++ + +error[E0107]: missing generics for trait `test_4::Trait` + --> $DIR/query-cycle-oom.rs:57:33 + | +LL | fn foo(&self, _: dyn Trait) {} + | ^^^^^ expected 1 generic argument + | +note: trait defined here, with 1 generic parameter: `T` + --> $DIR/query-cycle-oom.rs:56:11 + | +LL | trait Trait { + | ^^^^^ - +help: add missing generic argument + | +LL | fn foo(&self, _: dyn Trait) {} + | +++ + +error[E0220]: associated type `Assoc` not found for `Self` + --> $DIR/query-cycle-oom.rs:23:27 + | +LL | fn foo() -> Self::Assoc; + | ^^^^^ associated type `Assoc` not found + +error[E0220]: associated type `Assoc` not found for `Self` + --> $DIR/query-cycle-oom.rs:44:32 + | +LL | fn foo(&self) -> Self::Assoc<3> { + | ^^^^^ associated type `Assoc` not found + +error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions + --> $DIR/query-cycle-oom.rs:61:19 + | +LL | reuse Trait::<_>::foo:: as x; + | ^ not allowed in type signatures + +error[E0046]: not all trait items implemented, missing: `foo` + --> $DIR/query-cycle-oom.rs:28:5 + | +LL | fn foo() -> Self::Assoc; + | ------------------------ `foo` from trait +... +LL | impl Trait for u8 { + | ^^^^^^^^^^^^^^^^^ missing `foo` in implementation + +error[E0390]: cannot define inherent `impl` for primitive types + --> $DIR/query-cycle-oom.rs:49:5 + | +LL | impl () { + | ^^^^^^^ + | + = help: consider using an extension trait instead + +error[E0433]: cannot find module or crate `to_reuse` in this scope + --> $DIR/query-cycle-oom.rs:16:15 + | +LL | reuse to_reuse::foo { &self.0 } + | ^^^^^^^^ use of unresolved module or unlinked crate `to_reuse` + | + = help: you might be missing a crate named `to_reuse` + +error[E0061]: this function takes 0 arguments but 1 argument was supplied + --> $DIR/query-cycle-oom.rs:36:22 + | +LL | reuse Trait::* { &self.0 } + | ^ ------- unexpected argument + | +note: associated function defined here + --> $DIR/query-cycle-oom.rs:23:12 + | +LL | fn foo() -> Self::Assoc; + | ^^^ +help: remove the extra argument + | +LL - reuse Trait::* { &self.0 } +LL + reuse Trait::&self.0 } + | + +error[E0599]: no method named `foo` found for reference `&()` in the current scope + --> $DIR/query-cycle-oom.rs:50:22 + | +LL | reuse Trait::*; + | ^ method not found in `&()` + | + = help: items from traits can only be used if the trait is implemented and in scope + = note: the following traits define an item `foo`, perhaps you need to implement one of them: + candidate #1: `test_1::Trait` + candidate #2: `test_2::Trait` + candidate #3: `test_3::Trait` + candidate #4: `test_4::Trait` + +error: aborting due to 10 previous errors + +Some errors have detailed explanations: E0046, E0061, E0107, E0121, E0220, E0390, E0433, E0599. +For more information about an error, try `rustc --explain E0046`.