From 588dce14211bdfb1305c495f01c697e29e946e10 Mon Sep 17 00:00:00 2001 From: Bryanskiy Date: Mon, 26 Aug 2024 19:57:59 +0300 Subject: [PATCH] Delegation: support generics in associated delegation items --- .../src/collect/generics_of.rs | 16 +- .../src/collect/predicates_of.rs | 16 +- compiler/rustc_hir_analysis/src/delegation.rs | 245 ++++++++++++++---- .../error_reporting/infer/need_type_info.rs | 3 + .../generics/impl-to-free-fn-pass.rs | 29 +++ .../generics/impl-to-trait-method.rs | 44 ++++ .../generics/impl-to-trait-method.stderr | 49 ++++ .../impl-trait-to-trait-method-pass.rs | 77 ++++++ .../inherent-impl-to-trait-method-pass.rs | 23 ++ .../generics/trait-method-to-other-pass.rs | 30 +++ tests/ui/delegation/ice-issue-124347.rs | 4 +- tests/ui/delegation/ice-issue-124347.stderr | 14 +- tests/ui/delegation/unsupported.rs | 59 ----- tests/ui/delegation/unsupported.stderr | 165 ++---------- 14 files changed, 501 insertions(+), 273 deletions(-) create mode 100644 tests/ui/delegation/generics/impl-to-free-fn-pass.rs create mode 100644 tests/ui/delegation/generics/impl-to-trait-method.rs create mode 100644 tests/ui/delegation/generics/impl-to-trait-method.stderr create mode 100644 tests/ui/delegation/generics/impl-trait-to-trait-method-pass.rs create mode 100644 tests/ui/delegation/generics/inherent-impl-to-trait-method-pass.rs create mode 100644 tests/ui/delegation/generics/trait-method-to-other-pass.rs diff --git a/compiler/rustc_hir_analysis/src/collect/generics_of.rs b/compiler/rustc_hir_analysis/src/collect/generics_of.rs index 28d6cab4b43..e5f3d68caa5 100644 --- a/compiler/rustc_hir_analysis/src/collect/generics_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/generics_of.rs @@ -58,6 +58,12 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics { let hir_id = tcx.local_def_id_to_hir_id(def_id); let node = tcx.hir_node(hir_id); + if let Some(sig) = node.fn_sig() + && let Some(sig_id) = sig.decl.opt_delegation_sig_id() + { + return inherit_generics_for_delegation_item(tcx, def_id, sig_id); + } + let parent_def_id = match node { Node::ImplItem(_) | Node::TraitItem(_) @@ -228,16 +234,6 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics { // inherit the generics of the item. Some(parent.to_def_id()) } - ItemKind::Fn(sig, _, _) => { - // For a delegation item inherit generics from callee. - if let Some(sig_id) = sig.decl.opt_delegation_sig_id() - && let Some(generics) = - inherit_generics_for_delegation_item(tcx, def_id, sig_id) - { - return generics; - } - None - } _ => None, }, _ => None, diff --git a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs index 6ac4802b195..61ba4346c61 100644 --- a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs @@ -120,6 +120,12 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen let hir_id = tcx.local_def_id_to_hir_id(def_id); let node = tcx.hir_node(hir_id); + if let Some(sig) = node.fn_sig() + && let Some(sig_id) = sig.decl.opt_delegation_sig_id() + { + return inherit_predicates_for_delegation_item(tcx, def_id, sig_id); + } + let mut is_trait = None; let mut is_default_impl_trait = None; @@ -146,16 +152,6 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen ItemKind::Trait(_, _, _, self_bounds, ..) | ItemKind::TraitAlias(_, self_bounds) => { is_trait = Some(self_bounds); } - - ItemKind::Fn(sig, _, _) => { - // For a delegation item inherit predicates from callee. - if let Some(sig_id) = sig.decl.opt_delegation_sig_id() - && let Some(predicates) = - inherit_predicates_for_delegation_item(tcx, def_id, sig_id) - { - return predicates; - } - } _ => {} } }; diff --git a/compiler/rustc_hir_analysis/src/delegation.rs b/compiler/rustc_hir_analysis/src/delegation.rs index d7a0698b6b3..2c9f20b7840 100644 --- a/compiler/rustc_hir_analysis/src/delegation.rs +++ b/compiler/rustc_hir_analysis/src/delegation.rs @@ -1,3 +1,7 @@ +//! Support inheriting generic parameters and predicates for function delegation. +//! +//! For more information about delegation design, see the tracking issue #118212. + use std::assert_matches::debug_assert_matches; use rustc_data_structures::fx::FxHashMap; @@ -5,7 +9,7 @@ use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_middle::ty::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable}; use rustc_middle::ty::{self, Ty, TyCtxt}; -use rustc_span::ErrorGuaranteed; +use rustc_span::{ErrorGuaranteed, Span}; use rustc_type_ir::visit::TypeVisitableExt; type RemapTable = FxHashMap; @@ -76,24 +80,60 @@ fn fn_kind<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> FnKind { } } +/// Given the current context(caller and callee `FnKind`), it specifies +/// the policy of predicates and generic parameters inheritance. +#[derive(Clone, Copy, Debug, PartialEq)] +enum InheritanceKind { + /// Copying all predicates and parameters, including those of the parent + /// container. + /// + /// Boolean value defines whether the `Self` parameter or `Self: Trait` + /// predicate are copied. It's always equal to `false` except when + /// delegating from a free function to a trait method. + /// + /// FIXME(fn_delegation): This often leads to type inference + /// errors. Support providing generic arguments or restrict use sites. + WithParent(bool), + /// The trait implementation should be compatible with the original trait. + /// Therefore, for trait implementations only the method's own parameters + /// and predicates are copied. + Own, +} + struct GenericsBuilder<'tcx> { tcx: TyCtxt<'tcx>, sig_id: DefId, parent: Option, + inh_kind: InheritanceKind, } impl<'tcx> GenericsBuilder<'tcx> { fn new(tcx: TyCtxt<'tcx>, sig_id: DefId) -> GenericsBuilder<'tcx> { - GenericsBuilder { tcx, sig_id, parent: None } + GenericsBuilder { tcx, sig_id, parent: None, inh_kind: InheritanceKind::WithParent(false) } + } + + fn with_parent(mut self, parent: DefId) -> Self { + self.parent = Some(parent); + self + } + + fn with_inheritance_kind(mut self, inh_kind: InheritanceKind) -> Self { + self.inh_kind = inh_kind; + self } fn build(self) -> ty::Generics { let mut own_params = vec![]; let sig_generics = self.tcx.generics_of(self.sig_id); - if let Some(parent_def_id) = sig_generics.parent { + if let InheritanceKind::WithParent(has_self) = self.inh_kind + && let Some(parent_def_id) = sig_generics.parent + { let sig_parent_generics = self.tcx.generics_of(parent_def_id); own_params.append(&mut sig_parent_generics.own_params.clone()); + if !has_self { + own_params.remove(0); + } } own_params.append(&mut sig_generics.own_params.clone()); @@ -115,8 +155,16 @@ fn build(self) -> ty::Generics { let param_def_id_to_index = own_params.iter().map(|param| (param.def_id, param.index)).collect(); + let (parent_count, has_self) = if let Some(def_id) = self.parent { + let parent_generics = self.tcx.generics_of(def_id); + let parent_kind = self.tcx.def_kind(def_id); + (parent_generics.count(), parent_kind == DefKind::Trait) + } else { + (0, false) + }; + for (idx, param) in own_params.iter_mut().enumerate() { - param.index = idx as u32; + param.index = (idx + parent_count) as u32; // FIXME(fn_delegation): Default parameters are not inherited, because they are // not permitted in functions. Therefore, there are 2 options here: // @@ -133,10 +181,10 @@ fn build(self) -> ty::Generics { ty::Generics { parent: self.parent, - parent_count: 0, + parent_count, own_params, param_def_id_to_index, - has_self: false, + has_self, has_late_bound_regions: sig_generics.has_late_bound_regions, host_effect_index: sig_generics.host_effect_index, } @@ -145,9 +193,10 @@ fn build(self) -> ty::Generics { struct PredicatesBuilder<'tcx> { tcx: TyCtxt<'tcx>, - args: ty::GenericArgsRef<'tcx>, - parent: Option, sig_id: DefId, + parent: Option, + inh_kind: InheritanceKind, + args: ty::GenericArgsRef<'tcx>, } impl<'tcx> PredicatesBuilder<'tcx> { @@ -156,18 +205,76 @@ fn new( args: ty::GenericArgsRef<'tcx>, sig_id: DefId, ) -> PredicatesBuilder<'tcx> { - PredicatesBuilder { tcx, args, parent: None, sig_id } + PredicatesBuilder { + tcx, + sig_id, + parent: None, + inh_kind: InheritanceKind::WithParent(false), + args, + } + } + + fn with_parent(mut self, parent: DefId) -> Self { + self.parent = Some(parent); + self + } + + fn with_inheritance_kind(mut self, inh_kind: InheritanceKind) -> Self { + self.inh_kind = inh_kind; + self } fn build(self) -> ty::GenericPredicates<'tcx> { - let mut preds = vec![]; - - let sig_predicates = self.tcx.predicates_of(self.sig_id); - if let Some(parent) = sig_predicates.parent { - let sig_parent_preds = self.tcx.predicates_of(parent); - preds.extend(sig_parent_preds.instantiate_own(self.tcx, self.args)); + struct PredicatesCollector<'tcx> { + tcx: TyCtxt<'tcx>, + preds: Vec<(ty::Clause<'tcx>, Span)>, + args: ty::GenericArgsRef<'tcx>, } - preds.extend(sig_predicates.instantiate_own(self.tcx, self.args)); + + impl<'tcx> PredicatesCollector<'tcx> { + fn new(tcx: TyCtxt<'tcx>, args: ty::GenericArgsRef<'tcx>) -> PredicatesCollector<'tcx> { + PredicatesCollector { tcx, preds: vec![], args } + } + + fn with_own_preds( + mut self, + f: impl Fn(DefId) -> ty::GenericPredicates<'tcx>, + def_id: DefId, + ) -> Self { + let preds = f(def_id).instantiate_own(self.tcx, self.args); + self.preds.extend(preds); + self + } + + fn with_preds( + mut self, + f: impl Fn(DefId) -> ty::GenericPredicates<'tcx> + Copy, + def_id: DefId, + ) -> Self { + let preds = f(def_id); + if let Some(parent_def_id) = preds.parent { + self = self.with_own_preds(f, parent_def_id); + } + self.with_own_preds(f, def_id) + } + } + let collector = PredicatesCollector::new(self.tcx, self.args); + + // `explicit_predicates_of` is used here to avoid copying `Self: Trait` predicate. + // Note: `predicates_of` query can also add inferred outlives predicates, but that + // is not the case here as `sig_id` is either a trait or a function. + let preds = match self.inh_kind { + InheritanceKind::WithParent(false) => { + collector.with_preds(|def_id| self.tcx.explicit_predicates_of(def_id), self.sig_id) + } + InheritanceKind::WithParent(true) => { + collector.with_preds(|def_id| self.tcx.predicates_of(def_id), self.sig_id) + } + InheritanceKind::Own => { + collector.with_own_preds(|def_id| self.tcx.predicates_of(def_id), self.sig_id) + } + } + .preds; ty::GenericPredicates { parent: self.parent, @@ -214,7 +321,6 @@ fn create_generic_args<'tcx>( let caller_kind = fn_kind(tcx, def_id.into()); let callee_kind = fn_kind(tcx, sig_id); - match (caller_kind, callee_kind) { (FnKind::Free, FnKind::Free) | (FnKind::Free, FnKind::AssocTrait) @@ -224,14 +330,32 @@ fn create_generic_args<'tcx>( let args = ty::GenericArgs::identity_for_item(tcx, sig_id); builder.build_from_args(args) } - // FIXME(fn_delegation): Only `Self` param supported here. - (FnKind::AssocTraitImpl, FnKind::AssocTrait) - | (FnKind::AssocInherentImpl, FnKind::AssocTrait) => { + + (FnKind::AssocTraitImpl, FnKind::AssocTrait) => { + let callee_generics = tcx.generics_of(sig_id); + let parent = tcx.parent(def_id.into()); + let parent_args = + tcx.impl_trait_header(parent).unwrap().trait_ref.instantiate_identity().args; + + let trait_args = ty::GenericArgs::identity_for_item(tcx, sig_id); + let method_args = tcx.mk_args_from_iter(trait_args.iter().skip(callee_generics.parent_count)); + let method_args = builder.build_from_args(method_args); + + tcx.mk_args_from_iter(parent_args.iter().chain(method_args)) + } + + (FnKind::AssocInherentImpl, FnKind::AssocTrait) => { let parent = tcx.parent(def_id.into()); let self_ty = tcx.type_of(parent).instantiate_identity(); let generic_self_ty = ty::GenericArg::from(self_ty); - tcx.mk_args_from_iter(std::iter::once(generic_self_ty)) + + let trait_args = ty::GenericArgs::identity_for_item(tcx, sig_id); + let trait_args = builder.build_from_args(trait_args); + + let args = std::iter::once(generic_self_ty).chain(trait_args.iter().skip(1)); + tcx.mk_args_from_iter(args) } + // For trait impl's `sig_id` is always equal to the corresponding trait method. (FnKind::AssocTraitImpl, _) | (_, FnKind::AssocTraitImpl) @@ -240,27 +364,50 @@ fn create_generic_args<'tcx>( } } +// FIXME(fn_delegation): Move generics inheritance to the AST->HIR lowering. +// For now, generic parameters are not propagated to the generated call, +// which leads to inference errors: +// +// fn foo(x: i32) {} +// +// reuse foo as bar; +// desugaring: +// fn bar() { +// foo::<_>() // ERROR: type annotations needed +// } pub(crate) fn inherit_generics_for_delegation_item<'tcx>( tcx: TyCtxt<'tcx>, def_id: LocalDefId, sig_id: DefId, -) -> Option { +) -> ty::Generics { let builder = GenericsBuilder::new(tcx, sig_id); let caller_kind = fn_kind(tcx, def_id.into()); let callee_kind = fn_kind(tcx, sig_id); - - // FIXME(fn_delegation): Support generics on associated delegation items. - // Error will be reported in `check_constraints`. match (caller_kind, callee_kind) { (FnKind::Free, FnKind::Free) - | (FnKind::Free, FnKind::AssocTrait) => Some(builder.build()), + | (FnKind::Free, FnKind::AssocTrait) => builder.with_inheritance_kind(InheritanceKind::WithParent(true)).build(), - (FnKind::AssocTraitImpl, FnKind::AssocTrait) - | (FnKind::AssocInherentImpl, FnKind::AssocTrait) - | (FnKind::AssocTrait, FnKind::AssocTrait) - | (FnKind::AssocInherentImpl, FnKind::Free) - | (FnKind::AssocTrait, FnKind::Free) => None, + (FnKind::AssocTraitImpl, FnKind::AssocTrait) => { + builder + .with_parent(tcx.parent(def_id.into())) + .with_inheritance_kind(InheritanceKind::Own) + .build() + } + + (FnKind::AssocInherentImpl, FnKind::AssocTrait) + | (FnKind::AssocTrait, FnKind::AssocTrait) => { + builder + .with_parent(tcx.parent(def_id.into())) + .build() + } + + (FnKind::AssocInherentImpl, FnKind::Free) + | (FnKind::AssocTrait, FnKind::Free) => { + builder + .with_parent(tcx.parent(def_id.into())) + .build() + } // For trait impl's `sig_id` is always equal to the corresponding trait method. (FnKind::AssocTraitImpl, _) @@ -274,26 +421,33 @@ pub(crate) fn inherit_predicates_for_delegation_item<'tcx>( tcx: TyCtxt<'tcx>, def_id: LocalDefId, sig_id: DefId, -) -> Option> { +) -> ty::GenericPredicates<'tcx> { let args = create_generic_args(tcx, def_id, sig_id); let builder = PredicatesBuilder::new(tcx, args, sig_id); let caller_kind = fn_kind(tcx, def_id.into()); let callee_kind = fn_kind(tcx, sig_id); - - // FIXME(fn_delegation): Support generics on associated delegation items. - // Error will be reported in `check_constraints`. match (caller_kind, callee_kind) { (FnKind::Free, FnKind::Free) | (FnKind::Free, FnKind::AssocTrait) => { - Some(builder.build()) + builder.with_inheritance_kind(InheritanceKind::WithParent(true)).build() } - (FnKind::AssocTraitImpl, FnKind::AssocTrait) - | (FnKind::AssocInherentImpl, FnKind::AssocTrait) + (FnKind::AssocTraitImpl, FnKind::AssocTrait) => { + builder + .with_parent(tcx.parent(def_id.into())) + .with_inheritance_kind(InheritanceKind::Own) + .build() + } + + (FnKind::AssocInherentImpl, FnKind::AssocTrait) | (FnKind::AssocTrait, FnKind::AssocTrait) | (FnKind::AssocInherentImpl, FnKind::Free) - | (FnKind::AssocTrait, FnKind::Free) => None, + | (FnKind::AssocTrait, FnKind::Free) => { + builder + .with_parent(tcx.parent(def_id.into())) + .build() + } // For trait impl's `sig_id` is always equal to the corresponding trait method. (FnKind::AssocTraitImpl, _) @@ -328,19 +482,6 @@ fn check_constraints<'tcx>( emit("recursive delegation is not supported yet"); } - if fn_kind(tcx, def_id.into()) != FnKind::Free { - let sig_generics = tcx.generics_of(sig_id); - let parent = tcx.parent(def_id.into()); - let parent_generics = tcx.generics_of(parent); - - let parent_has_self = parent_generics.has_self as usize; - let sig_has_self = sig_generics.has_self as usize; - - if sig_generics.count() > sig_has_self || parent_generics.count() > parent_has_self { - emit("early bound generics are not supported for associated delegation items"); - } - } - ret } diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/need_type_info.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/need_type_info.rs index f6dd7898fb2..2d0a7ce47f6 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/need_type_info.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/need_type_info.rs @@ -1253,6 +1253,9 @@ fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) { && let Some(def_id) = self.typeck_results.type_dependent_def_id(expr.hir_id) && self.tecx.tcx.trait_of_item(def_id).is_some() && !has_impl_trait(def_id) + // FIXME(fn_delegation): In delegation item argument spans are equal to last path + // segment. This leads to ICE's when emitting `multipart_suggestion`. + && tcx.hir().opt_delegation_sig_id(expr.hir_id.owner.def_id).is_none() { let successor = method_args.get(0).map_or_else(|| (")", span.hi()), |arg| (", ", arg.span.lo())); diff --git a/tests/ui/delegation/generics/impl-to-free-fn-pass.rs b/tests/ui/delegation/generics/impl-to-free-fn-pass.rs new file mode 100644 index 00000000000..3b39a457467 --- /dev/null +++ b/tests/ui/delegation/generics/impl-to-free-fn-pass.rs @@ -0,0 +1,29 @@ +//@ run-pass +#![feature(fn_delegation)] +#![allow(incomplete_features)] + +mod to_reuse { + pub fn foo(_: T, y: U) -> U { y } +} + +trait Trait { + fn foo(&self, x: T) -> T { x } +} +struct F; +impl Trait for F {} + +struct S(F, T); + +impl Trait for S { + reuse to_reuse::foo { &self.0 } +} + +impl S { + reuse to_reuse::foo; +} + +fn main() { + let s = S(F, 42); + assert_eq!(S::::foo(F, 1), 1); + assert_eq!( as Trait<_>>::foo(&s, 1), 1); +} diff --git a/tests/ui/delegation/generics/impl-to-trait-method.rs b/tests/ui/delegation/generics/impl-to-trait-method.rs new file mode 100644 index 00000000000..39e32e2ed15 --- /dev/null +++ b/tests/ui/delegation/generics/impl-to-trait-method.rs @@ -0,0 +1,44 @@ +#![feature(fn_delegation)] +#![allow(incomplete_features)] + +mod bounds { + trait Trait0 {} + + trait Trait1 { + fn foo(&self) + where + T: Trait0, + U: Trait0, + Self: Trait0, + //~^ ERROR the trait bound `bounds::S: Trait0` is not satisfied + { + } + } + + struct F; + impl Trait1 for F {} + + struct S(F); + + impl Trait1 for S { + reuse Trait1::::foo { &self.0 } + //~^ ERROR the trait bound `bounds::F: Trait0` is not satisfied + } +} + +mod unconstrained_parameter { + trait Trait { + fn foo(&self) {} + } + + struct F; + impl Trait for F {} + + struct S(F); + impl S { + reuse Trait::foo { &self.0 } + //~^ ERROR type annotations needed + } +} + +fn main() {} diff --git a/tests/ui/delegation/generics/impl-to-trait-method.stderr b/tests/ui/delegation/generics/impl-to-trait-method.stderr new file mode 100644 index 00000000000..aeba30de043 --- /dev/null +++ b/tests/ui/delegation/generics/impl-to-trait-method.stderr @@ -0,0 +1,49 @@ +error[E0277]: the trait bound `bounds::S: Trait0` is not satisfied + --> $DIR/impl-to-trait-method.rs:12:19 + | +LL | Self: Trait0, + | ^^^^^^ the trait `Trait0` is not implemented for `bounds::S` + | +help: this trait has no implementations, consider adding one + --> $DIR/impl-to-trait-method.rs:5:5 + | +LL | trait Trait0 {} + | ^^^^^^^^^^^^ + = help: see issue #48214 +help: add `#![feature(trivial_bounds)]` to the crate attributes to enable + | +LL + #![feature(trivial_bounds)] + | + +error[E0277]: the trait bound `bounds::F: Trait0` is not satisfied + --> $DIR/impl-to-trait-method.rs:24:34 + | +LL | reuse Trait1::::foo { &self.0 } + | --- ^^^^^^^ the trait `Trait0` is not implemented for `bounds::F` + | | + | required by a bound introduced by this call + | +help: this trait has no implementations, consider adding one + --> $DIR/impl-to-trait-method.rs:5:5 + | +LL | trait Trait0 {} + | ^^^^^^^^^^^^ +note: required by a bound in `Trait1::foo` + --> $DIR/impl-to-trait-method.rs:12:19 + | +LL | fn foo(&self) + | --- required by a bound in this associated function +... +LL | Self: Trait0, + | ^^^^^^ required by this bound in `Trait1::foo` + +error[E0282]: type annotations needed + --> $DIR/impl-to-trait-method.rs:39:22 + | +LL | reuse Trait::foo { &self.0 } + | ^^^ cannot infer type for type parameter `T` declared on the trait `Trait` + +error: aborting due to 3 previous errors + +Some errors have detailed explanations: E0277, E0282. +For more information about an error, try `rustc --explain E0277`. diff --git a/tests/ui/delegation/generics/impl-trait-to-trait-method-pass.rs b/tests/ui/delegation/generics/impl-trait-to-trait-method-pass.rs new file mode 100644 index 00000000000..72440fe82d4 --- /dev/null +++ b/tests/ui/delegation/generics/impl-trait-to-trait-method-pass.rs @@ -0,0 +1,77 @@ +//@ run-pass + +#![feature(fn_delegation)] +#![allow(incomplete_features)] + +use std::iter::{Iterator, Map}; + +pub mod same_trait { + use super::*; + + pub struct MapOuter { + pub inner: Map + } + + impl Iterator for MapOuter + where + F: FnMut(I::Item) -> B, + { + type Item = as Iterator>::Item; + + reuse Iterator::{next, fold} { self.inner } + } +} +use same_trait::MapOuter; + +mod another_trait { + use super::*; + + trait ZipImpl { + type Item; + + fn next(&mut self) -> Option; + } + + pub struct Zip { + pub a: A, + pub b: B, + } + + impl ZipImpl for Zip { + type Item = (A::Item, B::Item); + + fn next(&mut self) -> Option<(A::Item, B::Item)> { + let x = self.a.next()?; + let y = self.b.next()?; + Some((x, y)) + } + } + + impl Iterator for Zip { + type Item = (A::Item, B::Item); + + // Parameters are inherited from `Iterator::next`, not from `ZipImpl::next`. + // Otherwise, there would be a compilation error due to an unconstrained parameter. + reuse ZipImpl::next; + } +} +use another_trait::Zip; + +fn main() { + { + let x = vec![1, 2, 3]; + let iter = x.iter().map(|val| val * 2); + let outer_iter = MapOuter { inner: iter }; + let val = outer_iter.fold(0, |acc, x| acc + x); + assert_eq!(val, 12); + } + + { + let x = vec![1, 2]; + let y = vec![4, 5]; + + let mut zip = Zip { a: x.iter(), b: y.iter() }; + assert_eq!(zip.next(), Some((&1, &4))); + assert_eq!(zip.next(), Some((&2, &5))); + } +} diff --git a/tests/ui/delegation/generics/inherent-impl-to-trait-method-pass.rs b/tests/ui/delegation/generics/inherent-impl-to-trait-method-pass.rs new file mode 100644 index 00000000000..6f3bb178971 --- /dev/null +++ b/tests/ui/delegation/generics/inherent-impl-to-trait-method-pass.rs @@ -0,0 +1,23 @@ +//@ run-pass + +#![feature(fn_delegation)] +#![allow(incomplete_features)] + +trait Trait { + fn foo(&self, x: T, y: U) -> (T, U) { + (x, y) + } +} + +impl Trait for () {} +struct S(T, ()); + +impl S { + reuse Trait::foo { self.1 } +} + + +fn main() { + let s = S((), ()); + assert_eq!(s.foo(1u32, 2i32), (1u32, 2i32)); +} diff --git a/tests/ui/delegation/generics/trait-method-to-other-pass.rs b/tests/ui/delegation/generics/trait-method-to-other-pass.rs new file mode 100644 index 00000000000..2094705a05c --- /dev/null +++ b/tests/ui/delegation/generics/trait-method-to-other-pass.rs @@ -0,0 +1,30 @@ +//@ run-pass + +#![feature(fn_delegation)] +#![allow(incomplete_features)] + +mod to_reuse { + pub fn foo(x: T) -> T { x } +} + +trait Trait1 { + fn foo(&self, _: T, x: U) -> U { x } +} + +#[derive(Default)] +struct F; + +impl Trait1 for F {} + +trait Trait2 { + fn get_f(&self) -> &F { &F } + reuse Trait1::foo as bar { self.get_f() } + reuse to_reuse::foo as baz; +} + +impl Trait2 for F {} + +fn main() { + assert_eq!(F.bar(1u8, 2u16), 2u16); + assert_eq!(F::baz(1u8), 1u8); +} diff --git a/tests/ui/delegation/ice-issue-124347.rs b/tests/ui/delegation/ice-issue-124347.rs index 3bfae8face5..ee2bf9e33eb 100644 --- a/tests/ui/delegation/ice-issue-124347.rs +++ b/tests/ui/delegation/ice-issue-124347.rs @@ -1,12 +1,12 @@ #![feature(fn_delegation)] #![allow(incomplete_features)] +// FIXME(fn_delegation): `recursive delegation` error should be emitted here trait Trait { reuse Trait::foo { &self.0 } - //~^ ERROR recursive delegation is not supported yet + //~^ ERROR cycle detected when computing generics of `Trait::foo` } -// FIXME(fn_delegation): `recursive delegation` error should be emitted here reuse foo; //~^ ERROR cycle detected when computing generics of `foo` diff --git a/tests/ui/delegation/ice-issue-124347.stderr b/tests/ui/delegation/ice-issue-124347.stderr index 87dd75ffec8..bd0bc970b94 100644 --- a/tests/ui/delegation/ice-issue-124347.stderr +++ b/tests/ui/delegation/ice-issue-124347.stderr @@ -1,8 +1,16 @@ -error: recursive delegation is not supported yet - --> $DIR/ice-issue-124347.rs:5:18 +error[E0391]: cycle detected when computing generics of `Trait::foo` + --> $DIR/ice-issue-124347.rs:6:18 | LL | reuse Trait::foo { &self.0 } - | ^^^ callee defined here + | ^^^ + | + = note: ...which immediately requires computing generics of `Trait::foo` again +note: cycle used when inheriting delegation signature + --> $DIR/ice-issue-124347.rs:6:18 + | +LL | reuse Trait::foo { &self.0 } + | ^^^ + = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information error[E0391]: cycle detected when computing generics of `foo` --> $DIR/ice-issue-124347.rs:10:7 diff --git a/tests/ui/delegation/unsupported.rs b/tests/ui/delegation/unsupported.rs index d5ac68ecf1b..e57effff48d 100644 --- a/tests/ui/delegation/unsupported.rs +++ b/tests/ui/delegation/unsupported.rs @@ -4,65 +4,6 @@ #![feature(fn_delegation)] #![allow(incomplete_features)] -mod generics { - trait GenericTrait { - fn bar(&self, x: T) -> T { x } - fn bar1() {} - } - trait Trait { - fn foo(&self, x: i32) -> i32 { x } - fn foo1<'a>(&self, x: &'a i32) -> &'a i32 { x } - fn foo2(&self, x: T) -> T { x } - fn foo3<'a: 'a>(_: &'a u32) {} - - reuse GenericTrait::bar; - //~^ ERROR early bound generics are not supported for associated delegation items - reuse GenericTrait::bar1; - //~^ ERROR early bound generics are not supported for associated delegation items - } - - struct F; - impl Trait for F {} - impl GenericTrait for F {} - - struct S(F); - - impl GenericTrait for S { - reuse >::bar { &self.0 } - //~^ ERROR early bound generics are not supported for associated delegation items - reuse GenericTrait::::bar1; - //~^ ERROR early bound generics are not supported for associated delegation items - } - - impl GenericTrait<()> for () { - reuse GenericTrait::bar { &F } - //~^ ERROR early bound generics are not supported for associated delegation items - reuse GenericTrait::bar1; - //~^ ERROR early bound generics are not supported for associated delegation items - } - - impl Trait for &S { - reuse Trait::foo; - //~^ ERROR early bound generics are not supported for associated delegation items - } - - impl Trait for S { - reuse Trait::foo1 { &self.0 } - reuse Trait::foo2 { &self.0 } - //~^ ERROR early bound generics are not supported for associated delegation items - //~| ERROR method `foo2` has 0 type parameters but its trait declaration has 1 type parameter - reuse ::foo3; - //~^ ERROR early bound generics are not supported for associated delegation items - //~| ERROR lifetime parameters or bounds on associated function `foo3` do not match the trait declaration - } - - struct GenericS(T); - impl Trait for GenericS { - reuse Trait::foo { &self.0 } - //~^ ERROR early bound generics are not supported for associated delegation items - } -} - mod opaque { trait Trait {} impl Trait for () {} diff --git a/tests/ui/delegation/unsupported.stderr b/tests/ui/delegation/unsupported.stderr index bb150254f48..03ded300bb4 100644 --- a/tests/ui/delegation/unsupported.stderr +++ b/tests/ui/delegation/unsupported.stderr @@ -3,125 +3,8 @@ error: using `#![feature(effects)]` without enabling next trait solver globally = note: the next trait solver must be enabled globally for the effects feature to work correctly = help: use `-Znext-solver` to enable -error: early bound generics are not supported for associated delegation items - --> $DIR/unsupported.rs:18:29 - | -LL | fn bar(&self, x: T) -> T { x } - | ------------------------ callee defined here -... -LL | reuse GenericTrait::bar; - | ^^^ - -error: early bound generics are not supported for associated delegation items - --> $DIR/unsupported.rs:20:29 - | -LL | fn bar1() {} - | --------- callee defined here -... -LL | reuse GenericTrait::bar1; - | ^^^^ - -error: early bound generics are not supported for associated delegation items - --> $DIR/unsupported.rs:31:39 - | -LL | fn bar(&self, x: T) -> T { x } - | ------------------------ callee defined here -... -LL | reuse >::bar { &self.0 } - | ^^^ - -error: early bound generics are not supported for associated delegation items - --> $DIR/unsupported.rs:33:34 - | -LL | fn bar1() {} - | --------- callee defined here -... -LL | reuse GenericTrait::::bar1; - | ^^^^ - -error: early bound generics are not supported for associated delegation items - --> $DIR/unsupported.rs:38:29 - | -LL | fn bar(&self, x: T) -> T { x } - | ------------------------ callee defined here -... -LL | reuse GenericTrait::bar { &F } - | ^^^ - -error: early bound generics are not supported for associated delegation items - --> $DIR/unsupported.rs:40:29 - | -LL | fn bar1() {} - | --------- callee defined here -... -LL | reuse GenericTrait::bar1; - | ^^^^ - -error: early bound generics are not supported for associated delegation items - --> $DIR/unsupported.rs:45:22 - | -LL | fn foo(&self, x: i32) -> i32 { x } - | ---------------------------- callee defined here -... -LL | reuse Trait::foo; - | ^^^ - -error[E0049]: method `foo2` has 0 type parameters but its trait declaration has 1 type parameter - --> $DIR/unsupported.rs:51:22 - | -LL | fn foo2(&self, x: T) -> T { x } - | - expected 1 type parameter -... -LL | reuse Trait::foo2 { &self.0 } - | ^^^^ found 0 type parameters - -error: early bound generics are not supported for associated delegation items - --> $DIR/unsupported.rs:54:29 - | -LL | fn foo3<'a: 'a>(_: &'a u32) {} - | --------------------------- callee defined here -... -LL | reuse ::foo3; - | ^^^^ - -error[E0195]: lifetime parameters or bounds on associated function `foo3` do not match the trait declaration - --> $DIR/unsupported.rs:54:29 - | -LL | fn foo3<'a: 'a>(_: &'a u32) {} - | -------- lifetimes in impl do not match this associated function in trait -... -LL | reuse ::foo3; - | ^^^^ lifetimes do not match associated function in trait - -error: delegation to a function with effect parameter is not supported yet - --> $DIR/unsupported.rs:112:18 - | -LL | fn foo(); - | --------- callee defined here -... -LL | reuse Trait::foo; - | ^^^ - -error: early bound generics are not supported for associated delegation items - --> $DIR/unsupported.rs:61:22 - | -LL | fn foo(&self, x: i32) -> i32 { x } - | ---------------------------- callee defined here -... -LL | reuse Trait::foo { &self.0 } - | ^^^ - -error: early bound generics are not supported for associated delegation items - --> $DIR/unsupported.rs:51:22 - | -LL | fn foo2(&self, x: T) -> T { x } - | ---------------------------- callee defined here -... -LL | reuse Trait::foo2 { &self.0 } - | ^^^^ - warning: this function depends on never type fallback being `()` - --> $DIR/unsupported.rs:79:9 + --> $DIR/unsupported.rs:20:9 | LL | fn opaque_ret() -> impl Trait { unimplemented!() } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -130,33 +13,33 @@ LL | fn opaque_ret() -> impl Trait { unimplemented!() } = note: for more information, see issue #123748 = help: specify the types explicitly note: in edition 2024, the requirement `!: opaque::Trait` will fail - --> $DIR/unsupported.rs:79:28 + --> $DIR/unsupported.rs:20:28 | LL | fn opaque_ret() -> impl Trait { unimplemented!() } | ^^^^^^^^^^ = note: `#[warn(dependency_on_unit_never_type_fallback)]` on by default -error[E0391]: cycle detected when computing type of `opaque::::{synthetic#0}` - --> $DIR/unsupported.rs:86:25 +error[E0391]: cycle detected when computing type of `opaque::::{synthetic#0}` + --> $DIR/unsupported.rs:27:25 | LL | reuse to_reuse::opaque_ret; | ^^^^^^^^^^ | note: ...which requires comparing an impl and trait method signature, inferring any hidden `impl Trait` types in the process... - --> $DIR/unsupported.rs:86:25 + --> $DIR/unsupported.rs:27:25 | LL | reuse to_reuse::opaque_ret; | ^^^^^^^^^^ - = note: ...which again requires computing type of `opaque::::{synthetic#0}`, completing the cycle -note: cycle used when checking that `opaque::` is well-formed - --> $DIR/unsupported.rs:85:5 + = note: ...which again requires computing type of `opaque::::{synthetic#0}`, completing the cycle +note: cycle used when checking that `opaque::` is well-formed + --> $DIR/unsupported.rs:26:5 | LL | impl ToReuse for u8 { | ^^^^^^^^^^^^^^^^^^^ = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information warning: this function depends on never type fallback being `()` - --> $DIR/unsupported.rs:73:9 + --> $DIR/unsupported.rs:14:9 | LL | pub fn opaque_ret() -> impl Trait { unimplemented!() } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -165,32 +48,32 @@ LL | pub fn opaque_ret() -> impl Trait { unimplemented!() } = note: for more information, see issue #123748 = help: specify the types explicitly note: in edition 2024, the requirement `!: opaque::Trait` will fail - --> $DIR/unsupported.rs:73:32 + --> $DIR/unsupported.rs:14:32 | LL | pub fn opaque_ret() -> impl Trait { unimplemented!() } | ^^^^^^^^^^ -error[E0391]: cycle detected when computing type of `opaque::::{synthetic#0}` - --> $DIR/unsupported.rs:89:24 +error[E0391]: cycle detected when computing type of `opaque::::{synthetic#0}` + --> $DIR/unsupported.rs:30:24 | LL | reuse ToReuse::opaque_ret; | ^^^^^^^^^^ | note: ...which requires comparing an impl and trait method signature, inferring any hidden `impl Trait` types in the process... - --> $DIR/unsupported.rs:89:24 + --> $DIR/unsupported.rs:30:24 | LL | reuse ToReuse::opaque_ret; | ^^^^^^^^^^ - = note: ...which again requires computing type of `opaque::::{synthetic#0}`, completing the cycle -note: cycle used when checking that `opaque::` is well-formed - --> $DIR/unsupported.rs:88:5 + = note: ...which again requires computing type of `opaque::::{synthetic#0}`, completing the cycle +note: cycle used when checking that `opaque::` is well-formed + --> $DIR/unsupported.rs:29:5 | LL | impl ToReuse for u16 { | ^^^^^^^^^^^^^^^^^^^^ = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information error: recursive delegation is not supported yet - --> $DIR/unsupported.rs:102:22 + --> $DIR/unsupported.rs:43:22 | LL | pub reuse to_reuse2::foo; | --- callee defined here @@ -198,7 +81,15 @@ LL | pub reuse to_reuse2::foo; LL | reuse to_reuse1::foo; | ^^^ -error: aborting due to 17 previous errors; 2 warnings emitted +error: delegation to a function with effect parameter is not supported yet + --> $DIR/unsupported.rs:53:18 + | +LL | fn foo(); + | --------- callee defined here +... +LL | reuse Trait::foo; + | ^^^ -Some errors have detailed explanations: E0049, E0195, E0391. -For more information about an error, try `rustc --explain E0049`. +error: aborting due to 5 previous errors; 2 warnings emitted + +For more information about this error, try `rustc --explain E0391`.