diff --git a/compiler/rustc_hir_analysis/src/collect/generics_of.rs b/compiler/rustc_hir_analysis/src/collect/generics_of.rs index be6c3f048dc..ba01ea3f512 100644 --- a/compiler/rustc_hir_analysis/src/collect/generics_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/generics_of.rs @@ -59,6 +59,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(_) @@ -229,16 +235,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 a47aaf25e95..7243e85ce98 100644 --- a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs @@ -138,6 +138,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; @@ -164,16 +170,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 20aaa43219f..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::DefKind; 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,127 +80,381 @@ 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, 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 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()); + + // Lifetime parameters must be declared before type and const parameters. + // Therefore, When delegating from a free function to a associated function, + // generic parameters need to be reordered: + // + // trait Trait<'a, A> { + // fn foo<'b, B>(...) {...} + // } + // + // reuse Trait::foo; + // desugaring: + // fn foo<'a, 'b, This: Trait<'a, A>, A, B>(...) { + // Trait::foo(...) + // } + own_params.sort_by_key(|key| key.kind.is_ty_or_const()); + + 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 + 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: + // + // - We can create non-default generic parameters. + // - We can substitute default parameters into the signature. + // + // At the moment, first option has been selected as the most general. + if let ty::GenericParamDefKind::Type { has_default, .. } + | ty::GenericParamDefKind::Const { has_default, .. } = &mut param.kind + { + *has_default = false; + } + } + + ty::Generics { + parent: self.parent, + parent_count, + own_params, + param_def_id_to_index, + has_self, + has_late_bound_regions: sig_generics.has_late_bound_regions, + host_effect_index: sig_generics.host_effect_index, + } + } +} + +struct PredicatesBuilder<'tcx> { + tcx: TyCtxt<'tcx>, + sig_id: DefId, + parent: Option, + inh_kind: InheritanceKind, + args: ty::GenericArgsRef<'tcx>, +} + +impl<'tcx> PredicatesBuilder<'tcx> { + fn new( + tcx: TyCtxt<'tcx>, + args: ty::GenericArgsRef<'tcx>, + sig_id: DefId, + ) -> PredicatesBuilder<'tcx> { + 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> { + struct PredicatesCollector<'tcx> { + tcx: TyCtxt<'tcx>, + preds: Vec<(ty::Clause<'tcx>, Span)>, + args: ty::GenericArgsRef<'tcx>, + } + + 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, + predicates: self.tcx.arena.alloc_from_iter(preds), + // FIXME(fn_delegation): Support effects. + effects_min_tys: ty::List::empty(), + } + } +} + +struct GenericArgsBuilder<'tcx> { + tcx: TyCtxt<'tcx>, + remap_table: RemapTable, + sig_id: DefId, + def_id: LocalDefId, +} + +impl<'tcx> GenericArgsBuilder<'tcx> { + fn new(tcx: TyCtxt<'tcx>, sig_id: DefId, def_id: LocalDefId) -> GenericArgsBuilder<'tcx> { + GenericArgsBuilder { tcx, remap_table: FxHashMap::default(), sig_id, def_id } + } + + fn build_from_args(mut self, args: ty::GenericArgsRef<'tcx>) -> ty::GenericArgsRef<'tcx> { + let caller_generics = self.tcx.generics_of(self.def_id); + let callee_generics = self.tcx.generics_of(self.sig_id); + + for caller_param in &caller_generics.own_params { + let callee_index = + callee_generics.param_def_id_to_index(self.tcx, caller_param.def_id).unwrap(); + self.remap_table.insert(callee_index, caller_param.index); + } + + let mut folder = ParamIndexRemapper { tcx: self.tcx, remap_table: self.remap_table }; + args.fold_with(&mut folder) + } +} + fn create_generic_args<'tcx>( tcx: TyCtxt<'tcx>, def_id: LocalDefId, sig_id: DefId, ) -> ty::GenericArgsRef<'tcx> { - let caller_generics = tcx.generics_of(def_id); - let callee_generics = tcx.generics_of(sig_id); + let builder = GenericArgsBuilder::new(tcx, sig_id, def_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, _) => { - // Lifetime parameters must be declared before type and const parameters. - // Therefore, When delegating from a free function to a associated function, - // generic parameters need to be reordered: - // - // trait Trait<'a, A> { - // fn foo<'b, B>(...) {...} - // } - // - // reuse Trait::foo; - // desugaring: - // fn foo<'a, 'b, This: Trait<'a, A>, A, B>(...) { - // Trait::foo(...) - // } - let mut remap_table = RemapTable::default(); - for caller_param in &caller_generics.own_params { - let callee_index = - callee_generics.param_def_id_to_index(tcx, caller_param.def_id).unwrap(); - remap_table.insert(callee_index, caller_param.index); - } - let mut folder = ParamIndexRemapper { tcx, remap_table }; - ty::GenericArgs::identity_for_item(tcx, sig_id).fold_with(&mut folder) + (FnKind::Free, FnKind::Free) + | (FnKind::Free, FnKind::AssocTrait) + | (FnKind::AssocInherentImpl, FnKind::Free) + | (FnKind::AssocTrait, FnKind::Free) + | (FnKind::AssocTrait, FnKind::AssocTrait) => { + 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) } - _ => ty::GenericArgs::identity_for_item(tcx, sig_id), + + // For trait impl's `sig_id` is always equal to the corresponding trait method. + (FnKind::AssocTraitImpl, _) + | (_, FnKind::AssocTraitImpl) + // Delegation to inherent methods is not yet supported. + | (_, FnKind::AssocInherentImpl) => unreachable!(), } } +// 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 { - // FIXME(fn_delegation): Support generics on associated delegation items. - // Error will be reported in `check_constraints`. - if fn_kind(tcx, def_id.into()) != FnKind::Free { - return None; - } +) -> ty::Generics { + let builder = GenericsBuilder::new(tcx, sig_id); - let mut own_params = vec![]; + 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) => builder.with_inheritance_kind(InheritanceKind::WithParent(true)).build(), - let callee_generics = tcx.generics_of(sig_id); - if let Some(parent_sig_id) = callee_generics.parent { - let parent_sig_generics = tcx.generics_of(parent_sig_id); - own_params.append(&mut parent_sig_generics.own_params.clone()); - } - own_params.append(&mut callee_generics.own_params.clone()); - - // Lifetimes go first. - own_params.sort_by_key(|key| key.kind.is_ty_or_const()); - - for (idx, param) in own_params.iter_mut().enumerate() { - param.index = idx as u32; - // Default parameters are not inherited: they are not allowed - // in fn's. - if let ty::GenericParamDefKind::Type { has_default, .. } - | ty::GenericParamDefKind::Const { has_default, .. } = &mut param.kind - { - *has_default = false; + (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, _) + | (_, FnKind::AssocTraitImpl) + // Delegation to inherent methods is not yet supported. + | (_, FnKind::AssocInherentImpl) => unreachable!(), } - - let param_def_id_to_index = - own_params.iter().map(|param| (param.def_id, param.index)).collect(); - - Some(ty::Generics { - parent: None, - parent_count: 0, - own_params, - param_def_id_to_index, - has_self: false, - has_late_bound_regions: callee_generics.has_late_bound_regions, - host_effect_index: callee_generics.host_effect_index, - }) } pub(crate) fn inherit_predicates_for_delegation_item<'tcx>( tcx: TyCtxt<'tcx>, def_id: LocalDefId, sig_id: DefId, -) -> Option> { - // FIXME(fn_delegation): Support generics on associated delegation items. - // Error will be reported in `check_constraints`. - if fn_kind(tcx, def_id.into()) != FnKind::Free { - return None; - } - - let callee_predicates = tcx.predicates_of(sig_id); +) -> ty::GenericPredicates<'tcx> { let args = create_generic_args(tcx, def_id, sig_id); + let builder = PredicatesBuilder::new(tcx, args, sig_id); - let mut preds = vec![]; - if let Some(parent_id) = callee_predicates.parent { - preds.extend(tcx.predicates_of(parent_id).instantiate_own(tcx, args)); + 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) => { + builder.with_inheritance_kind(InheritanceKind::WithParent(true)).build() + } + + (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) => { + 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, _) + | (_, FnKind::AssocTraitImpl) + // Delegation to inherent methods is not yet supported. + | (_, FnKind::AssocInherentImpl) => unreachable!(), } - preds.extend(callee_predicates.instantiate_own(tcx, args)); - - Some(ty::GenericPredicates { - parent: None, - predicates: tcx.arena.alloc_from_iter(preds), - effects_min_tys: ty::List::empty(), - }) } fn check_constraints<'tcx>( @@ -224,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 a93b633ce1a..cf9891f15ad 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 @@ -1296,6 +1296,9 @@ impl<'a, 'tcx> Visitor<'tcx> for FindInferSourceVisitor<'a, '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/not-supported.rs b/tests/ui/delegation/not-supported.rs deleted file mode 100644 index d5ac68ecf1b..00000000000 --- a/tests/ui/delegation/not-supported.rs +++ /dev/null @@ -1,116 +0,0 @@ -#![feature(const_trait_impl)] -#![feature(c_variadic)] -#![feature(effects)] -#![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 () {} - - mod to_reuse { - use super::Trait; - - pub fn opaque_ret() -> impl Trait { unimplemented!() } - //~^ warn: this function depends on never type fallback being `()` - //~| warn: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - } - - trait ToReuse { - fn opaque_ret() -> impl Trait { unimplemented!() } - //~^ warn: this function depends on never type fallback being `()` - //~| warn: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - } - - // FIXME: Inherited `impl Trait`s create query cycles when used inside trait impls. - impl ToReuse for u8 { - reuse to_reuse::opaque_ret; //~ ERROR cycle detected when computing type - } - impl ToReuse for u16 { - reuse ToReuse::opaque_ret; //~ ERROR cycle detected when computing type - } -} - -mod recursive { - mod to_reuse1 { - pub mod to_reuse2 { - pub fn foo() {} - } - - pub reuse to_reuse2::foo; - } - - reuse to_reuse1::foo; - //~^ ERROR recursive delegation is not supported yet -} - -mod effects { - #[const_trait] - trait Trait { - fn foo(); - } - - reuse Trait::foo; - //~^ ERROR delegation to a function with effect parameter is not supported yet -} - -fn main() {} diff --git a/tests/ui/delegation/not-supported.stderr b/tests/ui/delegation/not-supported.stderr deleted file mode 100644 index 14d6b374bd2..00000000000 --- a/tests/ui/delegation/not-supported.stderr +++ /dev/null @@ -1,204 +0,0 @@ -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/not-supported.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/not-supported.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/not-supported.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/not-supported.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/not-supported.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/not-supported.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/not-supported.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/not-supported.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/not-supported.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/not-supported.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/not-supported.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/not-supported.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/not-supported.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/not-supported.rs:79:9 - | -LL | fn opaque_ret() -> impl Trait { unimplemented!() } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #123748 - = help: specify the types explicitly -note: in edition 2024, the requirement `!: opaque::Trait` will fail - --> $DIR/not-supported.rs:79: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/not-supported.rs:86: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/not-supported.rs:86: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/not-supported.rs:85: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/not-supported.rs:73:9 - | -LL | pub fn opaque_ret() -> impl Trait { unimplemented!() } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #123748 - = help: specify the types explicitly -note: in edition 2024, the requirement `!: opaque::Trait` will fail - --> $DIR/not-supported.rs:73:32 - | -LL | pub fn opaque_ret() -> impl Trait { unimplemented!() } - | ^^^^^^^^^^ - -error[E0391]: cycle detected when computing type of `opaque::::{synthetic#0}` - --> $DIR/not-supported.rs:89: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/not-supported.rs:89: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/not-supported.rs:88: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/not-supported.rs:102:22 - | -LL | pub reuse to_reuse2::foo; - | --- callee defined here -... -LL | reuse to_reuse1::foo; - | ^^^ - -error: aborting due to 17 previous errors; 2 warnings emitted - -Some errors have detailed explanations: E0049, E0195, E0391. -For more information about an error, try `rustc --explain E0049`. diff --git a/tests/ui/delegation/unsupported.rs b/tests/ui/delegation/unsupported.rs new file mode 100644 index 00000000000..e57effff48d --- /dev/null +++ b/tests/ui/delegation/unsupported.rs @@ -0,0 +1,57 @@ +#![feature(const_trait_impl)] +#![feature(c_variadic)] +#![feature(effects)] +#![feature(fn_delegation)] +#![allow(incomplete_features)] + +mod opaque { + trait Trait {} + impl Trait for () {} + + mod to_reuse { + use super::Trait; + + pub fn opaque_ret() -> impl Trait { unimplemented!() } + //~^ warn: this function depends on never type fallback being `()` + //~| warn: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + } + + trait ToReuse { + fn opaque_ret() -> impl Trait { unimplemented!() } + //~^ warn: this function depends on never type fallback being `()` + //~| warn: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + } + + // FIXME: Inherited `impl Trait`s create query cycles when used inside trait impls. + impl ToReuse for u8 { + reuse to_reuse::opaque_ret; //~ ERROR cycle detected when computing type + } + impl ToReuse for u16 { + reuse ToReuse::opaque_ret; //~ ERROR cycle detected when computing type + } +} + +mod recursive { + mod to_reuse1 { + pub mod to_reuse2 { + pub fn foo() {} + } + + pub reuse to_reuse2::foo; + } + + reuse to_reuse1::foo; + //~^ ERROR recursive delegation is not supported yet +} + +mod effects { + #[const_trait] + trait Trait { + fn foo(); + } + + reuse Trait::foo; + //~^ ERROR delegation to a function with effect parameter is not supported yet +} + +fn main() {} diff --git a/tests/ui/delegation/unsupported.stderr b/tests/ui/delegation/unsupported.stderr new file mode 100644 index 00000000000..03ded300bb4 --- /dev/null +++ b/tests/ui/delegation/unsupported.stderr @@ -0,0 +1,95 @@ +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 + +warning: this function depends on never type fallback being `()` + --> $DIR/unsupported.rs:20:9 + | +LL | fn opaque_ret() -> impl Trait { unimplemented!() } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = 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 #123748 + = help: specify the types explicitly +note: in edition 2024, the requirement `!: opaque::Trait` will fail + --> $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: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: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: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:14:9 + | +LL | pub fn opaque_ret() -> impl Trait { unimplemented!() } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = 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 #123748 + = help: specify the types explicitly +note: in edition 2024, the requirement `!: opaque::Trait` will fail + --> $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: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: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: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:43:22 + | +LL | pub reuse to_reuse2::foo; + | --- callee defined here +... +LL | reuse to_reuse1::foo; + | ^^^ + +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; + | ^^^ + +error: aborting due to 5 previous errors; 2 warnings emitted + +For more information about this error, try `rustc --explain E0391`.