From f2b127872d6e3f1f9a83faf1a37c15036c024b43 Mon Sep 17 00:00:00 2001 From: Bryanskiy Date: Fri, 29 Mar 2024 17:10:38 +0300 Subject: [PATCH] Delegation: partial generics support --- compiler/rustc_ast_lowering/src/delegation.rs | 2 +- compiler/rustc_hir_analysis/messages.ftl | 4 - .../src/collect/generics_of.rs | 6 + .../src/collect/predicates_of.rs | 6 + compiler/rustc_hir_analysis/src/errors.rs | 10 - .../src/hir_ty_lowering/mod.rs | 95 +---- compiler/rustc_hir_typeck/messages.ftl | 4 + compiler/rustc_hir_typeck/src/delegation.rs | 402 ++++++++++++++++++ compiler/rustc_hir_typeck/src/errors.rs | 10 + compiler/rustc_hir_typeck/src/lib.rs | 10 +- .../rustc_hir_typeck/src/typeck_root_ctxt.rs | 11 +- compiler/rustc_middle/src/hir/map/mod.rs | 15 + compiler/rustc_middle/src/query/mod.rs | 5 + compiler/rustc_middle/src/ty/mod.rs | 8 + compiler/rustc_resolve/src/late.rs | 23 +- tests/ui/delegation/explicit-paths.rs | 2 - tests/ui/delegation/explicit-paths.stderr | 46 +- .../generics/free-fn-to-free-fn-pass.rs | 160 +++++++ .../delegation/generics/free-fn-to-free-fn.rs | 76 ++++ .../generics/free-fn-to-free-fn.stderr | 128 ++++++ .../generics/free-fn-to-trait-methods-pass.rs | 37 ++ .../generics/free-fn-to-trait-methods.rs | 33 ++ .../generics/free-fn-to-trait-methods.stderr | 79 ++++ tests/ui/delegation/not-supported.rs | 21 +- tests/ui/delegation/not-supported.stderr | 89 ++-- tests/ui/delegation/target-expr.rs | 5 +- tests/ui/delegation/target-expr.stderr | 43 +- 27 files changed, 1078 insertions(+), 252 deletions(-) create mode 100644 compiler/rustc_hir_typeck/src/delegation.rs create mode 100644 tests/ui/delegation/generics/free-fn-to-free-fn-pass.rs create mode 100644 tests/ui/delegation/generics/free-fn-to-free-fn.rs create mode 100644 tests/ui/delegation/generics/free-fn-to-free-fn.stderr create mode 100644 tests/ui/delegation/generics/free-fn-to-trait-methods-pass.rs create mode 100644 tests/ui/delegation/generics/free-fn-to-trait-methods.rs create mode 100644 tests/ui/delegation/generics/free-fn-to-trait-methods.stderr diff --git a/compiler/rustc_ast_lowering/src/delegation.rs b/compiler/rustc_ast_lowering/src/delegation.rs index 27f8a6eae02a9..8157bf848d24e 100644 --- a/compiler/rustc_ast_lowering/src/delegation.rs +++ b/compiler/rustc_ast_lowering/src/delegation.rs @@ -33,7 +33,7 @@ //! HIR ty lowering. //! //! Similarly generics, predicates and header are set to the "default" values. -//! In case of discrepancy with callee function the `NotSupportedDelegation` error will +//! In case of discrepancy with callee function the `UnsupportedDelegation` error will //! also be emitted during HIR ty lowering. use crate::{ImplTraitPosition, ResolverAstLoweringExt}; diff --git a/compiler/rustc_hir_analysis/messages.ftl b/compiler/rustc_hir_analysis/messages.ftl index cf492a2a3fee3..31361c13fe311 100644 --- a/compiler/rustc_hir_analysis/messages.ftl +++ b/compiler/rustc_hir_analysis/messages.ftl @@ -309,10 +309,6 @@ hir_analysis_must_implement_not_function_span_note = required by this annotation hir_analysis_must_implement_one_of_attribute = the `#[rustc_must_implement_one_of]` attribute must be used with at least 2 args -hir_analysis_not_supported_delegation = - {$descr} is not supported yet - .label = callee defined here - hir_analysis_only_current_traits_adt = `{$name}` is not defined in the current crate hir_analysis_only_current_traits_arbitrary = only traits defined in the current crate can be implemented for arbitrary types diff --git a/compiler/rustc_hir_analysis/src/collect/generics_of.rs b/compiler/rustc_hir_analysis/src/collect/generics_of.rs index 9af959681fbfa..86e840ba8f84e 100644 --- a/compiler/rustc_hir_analysis/src/collect/generics_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/generics_of.rs @@ -51,6 +51,12 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics { }; } + if tcx.hir().opt_delegation_sig_id(def_id).is_some() + && let Some(generics) = &tcx.lower_delegation_ty(def_id).generics + { + return generics.clone(); + } + let hir_id = tcx.local_def_id_to_hir_id(def_id); let node = tcx.hir_node(hir_id); diff --git a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs index 072bb7279016a..5916ad6d0b7ae 100644 --- a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs @@ -111,6 +111,12 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen None => {} } + if tcx.hir().opt_delegation_sig_id(def_id).is_some() + && let Some(predicates) = tcx.lower_delegation_ty(def_id).predicates + { + return predicates; + } + let hir_id = tcx.local_def_id_to_hir_id(def_id); let node = tcx.hir_node(hir_id); diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs index 1c99713b3ae18..6b74bd3708454 100644 --- a/compiler/rustc_hir_analysis/src/errors.rs +++ b/compiler/rustc_hir_analysis/src/errors.rs @@ -1569,16 +1569,6 @@ pub enum RefOfMutStaticSugg { }, } -#[derive(Diagnostic)] -#[diag(hir_analysis_not_supported_delegation)] -pub struct NotSupportedDelegation<'a> { - #[primary_span] - pub span: Span, - pub descr: &'a str, - #[label] - pub callee_span: Span, -} - #[derive(Diagnostic)] #[diag(hir_analysis_method_should_return_future)] pub struct MethodShouldReturnFuture { diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs index 3f66f971b171f..76bbda50b9e21 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -1939,94 +1939,11 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { self.lower_ty_common(hir_ty, false, true) } - fn check_delegation_constraints(&self, sig_id: DefId, span: Span, emit: bool) -> bool { - let mut error_occured = false; - let sig_span = self.tcx().def_span(sig_id); - let mut try_emit = |descr| { - if emit { - self.tcx().dcx().emit_err(crate::errors::NotSupportedDelegation { - span, - descr, - callee_span: sig_span, - }); - } - error_occured = true; - }; - - if let Some(node) = self.tcx().hir().get_if_local(sig_id) - && let Some(decl) = node.fn_decl() - && let hir::FnRetTy::Return(ty) = decl.output - && let hir::TyKind::InferDelegation(_, _) = ty.kind - { - try_emit("recursive delegation"); - } - - let sig_generics = self.tcx().generics_of(sig_id); - let parent = self.tcx().parent(self.item_def_id()); - let parent_generics = self.tcx().generics_of(parent); - - let parent_is_trait = (self.tcx().def_kind(parent) == DefKind::Trait) as usize; - let sig_has_self = sig_generics.has_self as usize; - - if sig_generics.count() > sig_has_self || parent_generics.count() > parent_is_trait { - try_emit("delegation with early bound generics"); - } - - // There is no way to instantiate `Self` param for caller if - // 1. callee is a trait method - // 2. delegation item isn't an associative item - if let DefKind::AssocFn = self.tcx().def_kind(sig_id) - && let DefKind::Fn = self.tcx().def_kind(self.item_def_id()) - && self.tcx().associated_item(sig_id).container - == ty::AssocItemContainer::TraitContainer - { - try_emit("delegation to a trait method from a free function"); - } - - error_occured - } - - fn lower_delegation_ty( - &self, - sig_id: DefId, - idx: hir::InferDelegationKind, - span: Span, - ) -> Ty<'tcx> { - if self.check_delegation_constraints(sig_id, span, idx == hir::InferDelegationKind::Output) - { - let e = self.tcx().dcx().span_delayed_bug(span, "not supported delegation case"); - self.set_tainted_by_errors(e); - return Ty::new_error(self.tcx(), e); - }; - let sig = self.tcx().fn_sig(sig_id); - let sig_generics = self.tcx().generics_of(sig_id); - - let parent = self.tcx().parent(self.item_def_id()); - let parent_def_kind = self.tcx().def_kind(parent); - - let sig = if let DefKind::Impl { .. } = parent_def_kind - && sig_generics.has_self - { - // Generic params can't be here except the trait self type. - // They are not supported yet. - assert_eq!(sig_generics.count(), 1); - assert_eq!(self.tcx().generics_of(parent).count(), 0); - - let self_ty = self.tcx().type_of(parent).instantiate_identity(); - let generic_self_ty = ty::GenericArg::from(self_ty); - let args = self.tcx().mk_args_from_iter(std::iter::once(generic_self_ty)); - sig.instantiate(self.tcx(), args) - } else { - sig.instantiate_identity() - }; - - // Bound vars are also inherited from `sig_id`. - // They will be rebound later in `lower_fn_ty`. - let sig = sig.skip_binder(); - + fn lower_delegation_ty(&self, idx: hir::InferDelegationKind) -> Ty<'tcx> { + let delegation_res = self.tcx().lower_delegation_ty(self.item_def_id().expect_local()); match idx { - hir::InferDelegationKind::Input(id) => sig.inputs()[id], - hir::InferDelegationKind::Output => sig.output(), + hir::InferDelegationKind::Input(idx) => delegation_res.inputs[idx], + hir::InferDelegationKind::Output => delegation_res.output, } } @@ -2043,9 +1960,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { let tcx = self.tcx(); let result_ty = match &hir_ty.kind { - hir::TyKind::InferDelegation(sig_id, idx) => { - self.lower_delegation_ty(*sig_id, *idx, hir_ty.span) - } + hir::TyKind::InferDelegation(_, idx) => self.lower_delegation_ty(*idx), hir::TyKind::Slice(ty) => Ty::new_slice(tcx, self.lower_ty(ty)), hir::TyKind::Ptr(mt) => Ty::new_ptr(tcx, self.lower_ty(mt.ty), mt.mutbl), hir::TyKind::Ref(region, mt) => { diff --git a/compiler/rustc_hir_typeck/messages.ftl b/compiler/rustc_hir_typeck/messages.ftl index 6f499947d5cd4..ea7ba4e6328ee 100644 --- a/compiler/rustc_hir_typeck/messages.ftl +++ b/compiler/rustc_hir_typeck/messages.ftl @@ -111,6 +111,10 @@ hir_typeck_no_associated_item = no {$item_kind} named `{$item_name}` found for { *[other] {" "}in the current scope } +hir_typeck_not_supported_delegation = + {$descr} + .label = callee defined here + hir_typeck_note_caller_chooses_ty_for_ty_param = the caller chooses a type for `{$ty_param_name}` which can be different from `{$found_ty}` hir_typeck_note_edition_guide = for more on editions, read https://doc.rust-lang.org/edition-guide diff --git a/compiler/rustc_hir_typeck/src/delegation.rs b/compiler/rustc_hir_typeck/src/delegation.rs new file mode 100644 index 0000000000000..f92da02469da5 --- /dev/null +++ b/compiler/rustc_hir_typeck/src/delegation.rs @@ -0,0 +1,402 @@ +use crate::{FnCtxt, TypeckRootCtxt}; + +use itertools::Itertools; +use rustc_data_structures::fx::FxIndexMap; +use rustc_hir as hir; +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, GenericArgsRef, GenericParamDef, GenericParamDefKind, Ty, TyCtxt, TypeSuperVisitable, + TypeVisitable, TypeVisitor, +}; +use rustc_span::ErrorGuaranteed; +use rustc_trait_selection::infer::TyCtxtInferExt; + +#[derive(Default)] +struct GenericDefsMap<'tcx> { + // Generic arguments of each type encountered in delegation path. + // For example in + // + // struct S { ... } + // reuse foo::>; + // + // it will contain { DefId(foo): S, DefId(S): ?0t }. Callee + // signature and predicates will be substituted with this arguments + // when the caller type is inherited. + defs: FxIndexMap>, + // Maps inference variables to corresponding type parameter definitions. + ty_defs: FxIndexMap, + // Maps inference variables to corresponding lifetime definitions. + region_defs: FxIndexMap, +} + +#[derive(Clone, Copy, Debug, PartialEq)] +enum FnKind { + Free, + AssocInherentImpl, + AssocTrait, + AssocTraitImpl, +} + +fn fn_kind<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> FnKind { + debug_assert!(matches!(tcx.def_kind(def_id), DefKind::Fn | DefKind::AssocFn)); + + let parent = tcx.parent(def_id); + match tcx.def_kind(parent) { + DefKind::Trait => FnKind::AssocTrait, + DefKind::Impl { of_trait: true } => FnKind::AssocTraitImpl, + DefKind::Impl { of_trait: false } => FnKind::AssocInherentImpl, + _ => FnKind::Free, + } +} + +struct GenericDefsCollector<'tcx> { + tcx: TyCtxt<'tcx>, + info: GenericDefsMap<'tcx>, + def_id: LocalDefId, +} + +impl<'tcx> GenericDefsCollector<'tcx> { + fn new(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> GenericDefsCollector<'tcx> { + GenericDefsCollector { tcx, info: GenericDefsMap::default(), def_id } + } + + fn collect(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> GenericDefsMap<'tcx> { + let mut collector = GenericDefsCollector::new(tcx, def_id); + let caller_kind = fn_kind(tcx, def_id.into()); + // FIXME(fn_delegation): Support generics on associated delegation items. + // Error was reported earlier in `check_constraints`. + if caller_kind == FnKind::Free { + let path = collector.check_call(); + path.visit_with(&mut collector); + } + + collector.info + } + + // Collect generic parameter definitions during callee type traversal according to + // encountered inference variables. + fn extract_info_from_def(&mut self, def_id: DefId, args: GenericArgsRef<'tcx>) { + let generics = self.tcx.generics_of(def_id); + + for (idx, arg) in args.iter().enumerate() { + if let Some(ty) = arg.as_type() + && let ty::Infer(ty::InferTy::TyVar(ty_vid)) = ty.kind() + { + self.info.ty_defs.insert(*ty_vid, generics.param_at(idx, self.tcx).clone()); + } else if let Some(re) = arg.as_region() + && let ty::RegionKind::ReVar(inf_re) = re.kind() + { + self.info.region_defs.insert(inf_re, generics.param_at(idx, self.tcx).clone()); + } + } + + self.info.defs.insert(def_id, args); + } + + // Extract callee type from the call path. Should only be used for + // non-associated delegation items. For example in + // + // trait Trait { + // fn foo(&self, x: U, y: T); + // } + // + // reuse >::foo; + // + // it will return `FnDef(DefId(Trait::foo), [u16, ?0t, ?1t])`. + fn check_call(&self) -> Ty<'tcx> { + let body = self.tcx.hir().body_owned_by(self.def_id); + let body = self.tcx.hir().body(body); + + let (expr, callee, args) = match body.value.kind { + hir::ExprKind::Block( + hir::Block { + expr: expr @ Some(hir::Expr { kind: hir::ExprKind::Call(callee, args), .. }), + .. + }, + _, + ) => (expr.unwrap(), callee, args), + _ => unreachable!(), + }; + + let infcx = self.tcx.infer_ctxt().ignoring_regions().build(); + // FIXME: cycle error on `with_opaque_type_inference` + let root_ctxt = TypeckRootCtxt::new_with_infcx(self.tcx, self.def_id, infcx); + let param_env = ty::ParamEnv::empty(); + let fcx = FnCtxt::new(&root_ctxt, param_env, self.def_id); + fcx.check_expr_with_expectation_and_args( + callee, + crate::expectation::Expectation::NoExpectation, + args, + Some(expr), + ) + } +} + +impl<'tcx> TypeVisitor> for GenericDefsCollector<'tcx> { + fn visit_ty(&mut self, ty: Ty<'tcx>) { + match ty.kind() { + ty::Adt(adt, args) => self.extract_info_from_def(adt.did(), args), + ty::FnDef(did, args) => self.extract_info_from_def(*did, args), + _ => {} + } + + ty.super_visit_with(self) + } +} + +struct DelegationArgFolder<'tcx, 'a> { + tcx: TyCtxt<'tcx>, + info: &'a GenericDefsMap<'tcx>, +} + +impl<'tcx, 'a> DelegationArgFolder<'tcx, 'a> { + fn new(tcx: TyCtxt<'tcx>, info: &'a GenericDefsMap<'tcx>) -> DelegationArgFolder<'tcx, 'a> { + DelegationArgFolder { tcx, info } + } +} + +impl<'tcx, 'a> TypeFolder> for DelegationArgFolder<'tcx, 'a> { + fn interner(&self) -> TyCtxt<'tcx> { + self.tcx + } + + fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> { + if let ty::Infer(inf_ty) = ty.kind() + && let ty::InferTy::TyVar(vid) = inf_ty + { + let param = self.info.ty_defs[vid].clone(); + let index = vid.as_u32() + self.info.region_defs.len() as u32; + return Ty::new_param(self.tcx, index, param.name); + }; + ty.super_fold_with(self) + } + + fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> { + let ty::RegionKind::ReVar(rid) = &r.kind() else { + return r; + }; + let param = &self.info.region_defs[rid]; + ty::Region::new_early_param( + self.tcx, + ty::EarlyParamRegion { index: rid.as_u32(), name: param.name }, + ) + } +} + +struct DelegationLowerer<'tcx, 'a> { + tcx: TyCtxt<'tcx>, + info: &'a GenericDefsMap<'tcx>, + def_id: LocalDefId, + sig_id: DefId, +} + +impl<'tcx, 'a> DelegationLowerer<'tcx, 'a> { + fn new( + tcx: TyCtxt<'tcx>, + def_id: LocalDefId, + info: &'a GenericDefsMap<'tcx>, + ) -> DelegationLowerer<'tcx, 'a> { + DelegationLowerer { tcx, info, def_id, sig_id: tcx.hir().delegation_sig_id(def_id) } + } + + fn fn_sig(&self) -> (&'tcx [Ty<'tcx>], Ty<'tcx>) { + let caller_sig = self.tcx.fn_sig(self.sig_id); + + let caller_kind = fn_kind(self.tcx, self.def_id.into()); + let callee_kind = fn_kind(self.tcx, self.sig_id); + + // FIXME(fn_delegation): Support generics on associated delegation items. + // Error was reported earlier in `check_constraints`. + let sig = match (caller_kind, callee_kind) { + (FnKind::Free, _) => { + let mut args = self.info.defs[&self.sig_id]; + let mut folder = DelegationArgFolder::new(self.tcx, self.info); + args = args.fold_with(&mut folder); + + caller_sig.instantiate(self.tcx, args) + } + // only `Self` param supported here + (FnKind::AssocTraitImpl, FnKind::AssocTrait) + | (FnKind::AssocInherentImpl, FnKind::AssocTrait) => { + let parent = self.tcx.parent(self.def_id.into()); + let self_ty = self.tcx.type_of(parent).instantiate_identity(); + let generic_self_ty = ty::GenericArg::from(self_ty); + let args = self.tcx.mk_args_from_iter(std::iter::once(generic_self_ty)); + caller_sig.instantiate(self.tcx, args) + } + _ => caller_sig.instantiate_identity(), + }; + // Bound vars are also inherited from `sig_id`. + // They will be rebound later in `lower_fn_ty`. + let sig = sig.skip_binder(); + (sig.inputs(), sig.output()) + } + + // Type parameters may not be specified in callee path because they are inferred by compiler. + // In contrast, constants must always be specified explicitly if the parameter is + // not defined by default: + // + // fn foo() {} + // + // reuse foo as bar; + // // desugaring with inherited type info: + // fn bar() { + // foo() // ERROR: cannot infer the value of the const parameter `N` + // } + // + // Due to implementation limitations, the callee path is lowered without modifications. + // As a result, we get a compilation error. Therefore, we do not inherit const parameters, + // but they can be specified as generic arguments: + // + // fn foo() {} + // + // reuse foo::<1> as bar; + // // desugaring with inherited type info: + // fn bar() { + // foo::<1>() + // } + fn generics_of(&self) -> Option { + let callee_generics = self.tcx.generics_of(self.sig_id); + + let caller_kind = fn_kind(self.tcx, self.def_id.into()); + let callee_kind = fn_kind(self.tcx, self.sig_id); + + // FIXME(fn_delegation): Support generics on associated delegation items. + // Error was reported earlier in `check_constraints`. + match (caller_kind, callee_kind) { + (FnKind::Free, _) => { + let mut ty_params = + self.info.ty_defs.iter().map(|(_, param)| param.clone()).collect_vec(); + let mut region_params = + self.info.region_defs.iter().map(|(_, param)| param.clone()).collect_vec(); + + region_params.append(&mut ty_params); + let mut own_params = region_params; + + for (idx, param) in own_params.iter_mut().enumerate() { + param.index = idx as u32; + // Default type parameters are not inherited: they are not allowed + // in fn's. + if let GenericParamDefKind::Type { synthetic, .. } = param.kind { + param.kind = GenericParamDefKind::Type { has_default: false, synthetic } + } + } + + 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: None, + }) + } + _ => None, + } + } + + fn predicates_of(&self) -> Option> { + let caller_kind = fn_kind(self.tcx, self.def_id.into()); + let callee_kind = fn_kind(self.tcx, self.sig_id); + + // FIXME(fn_delegation): Support generics on associated delegation items. + // Error was reported earlier in `check_constraints`. + match (caller_kind, callee_kind) { + (FnKind::Free, _) => { + let mut predicates = vec![]; + for (def_id, args) in self.info.defs.iter() { + let def_predicates = self.tcx.explicit_predicates_of(def_id); + let mut instantiated_predicates = + def_predicates.instantiate(self.tcx, args).into_iter().collect_vec(); + predicates.append(&mut instantiated_predicates); + } + + let span = self.tcx.def_span(self.def_id); + for predicate in predicates.iter_mut() { + predicate.1 = span; + } + + let mut folder = DelegationArgFolder::new(self.tcx, self.info); + let predicates = predicates.fold_with(&mut folder); + let predicates = self.tcx.arena.alloc_from_iter(predicates); + Some(ty::GenericPredicates { parent: None, predicates }) + } + _ => None, + } + } +} + +fn check_constraints<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Result<(), ErrorGuaranteed> { + let mut ret = Ok(()); + + let span = tcx.def_span(def_id); + let sig_id = tcx.hir().delegation_sig_id(def_id); + + let sig_span = tcx.def_span(sig_id); + let mut emit = |descr| { + ret = Err(tcx.dcx().emit_err(crate::errors::UnsupportedDelegation { + span, + descr, + callee_span: sig_span, + })); + }; + + if let Some(node) = tcx.hir().get_if_local(sig_id) + && let Some(decl) = node.fn_decl() + && let hir::FnRetTy::Return(ty) = decl.output + && let hir::TyKind::InferDelegation(_, _) = ty.kind + { + emit("recursive delegation is not supported yet"); + } + + let caller_kind = fn_kind(tcx, def_id.into()); + if caller_kind != 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_is_trait = (tcx.def_kind(parent) == DefKind::Trait) as usize; + let sig_has_self = sig_generics.has_self as usize; + + if sig_generics.count() > sig_has_self || parent_generics.count() > parent_is_trait { + emit("early bound generics are not supported for associated delegation items"); + } + } + + ret +} + +fn generate_error_results<'tcx>( + tcx: TyCtxt<'tcx>, + def_id: LocalDefId, + err: ErrorGuaranteed, +) -> ty::LoweredDelegation<'tcx> { + let sig_id = tcx.hir().delegation_sig_id(def_id); + let sig_len = tcx.fn_arg_names(sig_id).len(); + let err_type = Ty::new_error(tcx, err); + let inputs = tcx.arena.alloc_from_iter((0..sig_len).map(|_| err_type)); + ty::LoweredDelegation { inputs, output: err_type, generics: None, predicates: None } +} + +pub fn lower_delegation_ty<'tcx>( + tcx: TyCtxt<'tcx>, + def_id: LocalDefId, +) -> ty::LoweredDelegation<'tcx> { + if let Err(err) = check_constraints(tcx, def_id) { + return generate_error_results(tcx, def_id, err); + } + + let info = GenericDefsCollector::collect(tcx, def_id); + let delegation_resolver = DelegationLowerer::new(tcx, def_id, &info); + let (inputs, output) = delegation_resolver.fn_sig(); + let generics = delegation_resolver.generics_of(); + let predicates = delegation_resolver.predicates_of(); + + ty::LoweredDelegation { inputs, output, generics, predicates } +} diff --git a/compiler/rustc_hir_typeck/src/errors.rs b/compiler/rustc_hir_typeck/src/errors.rs index 3f12f25265454..dc9ff5fef57f1 100644 --- a/compiler/rustc_hir_typeck/src/errors.rs +++ b/compiler/rustc_hir_typeck/src/errors.rs @@ -679,3 +679,13 @@ pub struct ReplaceWithName { pub span: Span, pub name: String, } + +#[derive(Diagnostic)] +#[diag(hir_typeck_not_supported_delegation)] +pub struct UnsupportedDelegation<'a> { + #[primary_span] + pub span: Span, + pub descr: &'a str, + #[label] + pub callee_span: Span, +} diff --git a/compiler/rustc_hir_typeck/src/lib.rs b/compiler/rustc_hir_typeck/src/lib.rs index 86fe2756b59a0..824a0f14da74b 100644 --- a/compiler/rustc_hir_typeck/src/lib.rs +++ b/compiler/rustc_hir_typeck/src/lib.rs @@ -18,6 +18,7 @@ pub mod cast; mod check; mod closure; mod coercion; +mod delegation; mod demand; mod diverges; mod errors; @@ -39,6 +40,7 @@ mod upvar; mod writeback; pub use coercion::can_coerce; +use delegation::lower_delegation_ty; use fn_ctxt::FnCtxt; use typeck_root_ctxt::TypeckRootCtxt; @@ -415,5 +417,11 @@ fn fatally_break_rust(tcx: TyCtxt<'_>, span: Span) -> ! { pub fn provide(providers: &mut Providers) { method::provide(providers); - *providers = Providers { typeck, diagnostic_only_typeck, used_trait_imports, ..*providers }; + *providers = Providers { + typeck, + diagnostic_only_typeck, + used_trait_imports, + lower_delegation_ty, + ..*providers + }; } diff --git a/compiler/rustc_hir_typeck/src/typeck_root_ctxt.rs b/compiler/rustc_hir_typeck/src/typeck_root_ctxt.rs index 19d6481cc1b8b..46d7034a848ea 100644 --- a/compiler/rustc_hir_typeck/src/typeck_root_ctxt.rs +++ b/compiler/rustc_hir_typeck/src/typeck_root_ctxt.rs @@ -76,9 +76,16 @@ impl<'tcx> Deref for TypeckRootCtxt<'tcx> { impl<'tcx> TypeckRootCtxt<'tcx> { pub fn new(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Self { - let hir_owner = tcx.local_def_id_to_hir_id(def_id).owner; - let infcx = tcx.infer_ctxt().ignoring_regions().with_opaque_type_inference(def_id).build(); + Self::new_with_infcx(tcx, def_id, infcx) + } + + pub(super) fn new_with_infcx( + tcx: TyCtxt<'tcx>, + def_id: LocalDefId, + infcx: InferCtxt<'tcx>, + ) -> Self { + let hir_owner = tcx.local_def_id_to_hir_id(def_id).owner; let typeck_results = RefCell::new(ty::TypeckResults::new(hir_owner)); TypeckRootCtxt { diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs index ff8d291970556..61b086a55c25e 100644 --- a/compiler/rustc_middle/src/hir/map/mod.rs +++ b/compiler/rustc_middle/src/hir/map/mod.rs @@ -736,6 +736,21 @@ impl<'hir> Map<'hir> { } } + pub fn opt_delegation_sig_id(self, def_id: LocalDefId) -> Option { + if let Some(ret) = self.get_fn_output(def_id) + && let FnRetTy::Return(ty) = ret + && let TyKind::InferDelegation(sig_id, _) = ty.kind + { + return Some(sig_id); + } + None + } + + #[inline] + pub fn delegation_sig_id(self, def_id: LocalDefId) -> DefId { + self.opt_delegation_sig_id(def_id).unwrap() + } + #[inline] fn opt_ident(self, id: HirId) -> Option { match self.tcx.hir_node(id) { diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 6ad4b7c40fb2a..30b66bf092d8f 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -1666,6 +1666,11 @@ rustc_queries! { desc { |tcx| "getting the native library for `{}`", tcx.def_path_str(def_id) } } + query lower_delegation_ty(_: LocalDefId) -> &'tcx ty::LoweredDelegation<'tcx> { + arena_cache + desc { "inheriting delegation type" } + } + /// Does lifetime resolution on items. Importantly, we can't resolve /// lifetimes directly on things like trait methods, because of trait params. /// See `rustc_resolve::late::lifetimes` for details. diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index f24074cb472d9..4a37c936950a8 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -2130,6 +2130,14 @@ pub struct DestructuredConst<'tcx> { pub fields: &'tcx [ty::Const<'tcx>], } +#[derive(Clone, Debug, HashStable)] +pub struct LoweredDelegation<'tcx> { + pub inputs: &'tcx [Ty<'tcx>], + pub output: Ty<'tcx>, + pub generics: Option, + pub predicates: Option>, +} + // Some types are used a lot. Make sure they don't unintentionally get bigger. #[cfg(target_pointer_width = "64")] mod size_asserts { diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 0655484ad851c..046594d7e1367 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -3240,16 +3240,19 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { } fn resolve_delegation(&mut self, delegation: &'ast Delegation) { - self.smart_resolve_path( - delegation.id, - &delegation.qself, - &delegation.path, - PathSource::Delegation, - ); - if let Some(qself) = &delegation.qself { - self.visit_ty(&qself.ty); - } - self.visit_path(&delegation.path, delegation.id); + self.with_lifetime_rib(LifetimeRibKind::Elided(LifetimeRes::Infer), |this| { + this.smart_resolve_path( + delegation.id, + &delegation.qself, + &delegation.path, + PathSource::Delegation, + ); + + if let Some(qself) = &delegation.qself { + this.visit_ty(&qself.ty); + } + this.visit_path(&delegation.path, delegation.id); + }); if let Some(body) = &delegation.body { // `PatBoundCtx` is not necessary in this context let mut bindings = smallvec![(PatBoundCtx::Product, Default::default())]; diff --git a/tests/ui/delegation/explicit-paths.rs b/tests/ui/delegation/explicit-paths.rs index a91ca4cb931ed..c788ff428e5e8 100644 --- a/tests/ui/delegation/explicit-paths.rs +++ b/tests/ui/delegation/explicit-paths.rs @@ -22,9 +22,7 @@ mod fn_to_other { use super::*; reuse Trait::foo1; - //~^ ERROR delegation to a trait method from a free function is not supported yet reuse ::foo2; - //~^ ERROR delegation to a trait method from a free function is not supported yet reuse to_reuse::foo3; reuse S::foo4; //~^ ERROR cannot find function `foo4` in `S` diff --git a/tests/ui/delegation/explicit-paths.stderr b/tests/ui/delegation/explicit-paths.stderr index 30891c94c0e98..3bbef14986890 100644 --- a/tests/ui/delegation/explicit-paths.stderr +++ b/tests/ui/delegation/explicit-paths.stderr @@ -1,5 +1,5 @@ error[E0407]: method `foo3` is not a member of trait `Trait` - --> $DIR/explicit-paths.rs:51:9 + --> $DIR/explicit-paths.rs:49:9 | LL | reuse to_reuse::foo3; | ^^^^^^^^^^^^^^^^----^ @@ -8,7 +8,7 @@ LL | reuse to_reuse::foo3; | not a member of trait `Trait` error[E0407]: method `foo4` is not a member of trait `Trait` - --> $DIR/explicit-paths.rs:53:9 + --> $DIR/explicit-paths.rs:51:9 | LL | reuse F::foo4 { &self.0 } | ^^^^^^^^^----^^^^^^^^^^^^ @@ -17,49 +17,49 @@ LL | reuse F::foo4 { &self.0 } | not a member of trait `Trait` error[E0425]: cannot find function `foo4` in `S` - --> $DIR/explicit-paths.rs:29:14 + --> $DIR/explicit-paths.rs:27:14 | LL | reuse S::foo4; | ^^^^ not found in `S` error[E0425]: cannot find function `foo4` in `F` - --> $DIR/explicit-paths.rs:40:18 + --> $DIR/explicit-paths.rs:38:18 | LL | reuse F::foo4 { &self.0 } | ^^^^ not found in `F` | note: function `fn_to_other::foo4` exists but is inaccessible - --> $DIR/explicit-paths.rs:29:5 + --> $DIR/explicit-paths.rs:27:5 | LL | reuse S::foo4; | ^^^^^^^^^^^^^^ not accessible error[E0425]: cannot find function `foo4` in `F` - --> $DIR/explicit-paths.rs:53:18 + --> $DIR/explicit-paths.rs:51:18 | LL | reuse F::foo4 { &self.0 } | ^^^^ not found in `F` | note: function `fn_to_other::foo4` exists but is inaccessible - --> $DIR/explicit-paths.rs:29:5 + --> $DIR/explicit-paths.rs:27:5 | LL | reuse S::foo4; | ^^^^^^^^^^^^^^ not accessible error[E0425]: cannot find function `foo4` in `F` - --> $DIR/explicit-paths.rs:67:18 + --> $DIR/explicit-paths.rs:65:18 | LL | reuse F::foo4 { &F } | ^^^^ not found in `F` | note: function `fn_to_other::foo4` exists but is inaccessible - --> $DIR/explicit-paths.rs:29:5 + --> $DIR/explicit-paths.rs:27:5 | LL | reuse S::foo4; | ^^^^^^^^^^^^^^ not accessible error[E0119]: conflicting implementations of trait `Trait` for type `S` - --> $DIR/explicit-paths.rs:76:5 + --> $DIR/explicit-paths.rs:74:5 | LL | impl Trait for S { | ---------------- first implementation here @@ -67,26 +67,8 @@ LL | impl Trait for S { LL | impl Trait for S { | ^^^^^^^^^^^^^^^^ conflicting implementation for `S` -error: delegation to a trait method from a free function is not supported yet - --> $DIR/explicit-paths.rs:24:18 - | -LL | fn foo1(&self, x: i32) -> i32 { x } - | ----------------------------- callee defined here -... -LL | reuse Trait::foo1; - | ^^^^ - -error: delegation to a trait method from a free function is not supported yet - --> $DIR/explicit-paths.rs:26:25 - | -LL | fn foo2(x: i32) -> i32 { x } - | ---------------------- callee defined here -... -LL | reuse ::foo2; - | ^^^^ - error[E0308]: mismatched types - --> $DIR/explicit-paths.rs:63:36 + --> $DIR/explicit-paths.rs:61:36 | LL | trait Trait2 : Trait { | -------------------- found this type parameter @@ -97,7 +79,7 @@ LL | reuse ::foo1 { self } found reference `&Self` error[E0277]: the trait bound `S2: Trait` is not satisfied - --> $DIR/explicit-paths.rs:78:16 + --> $DIR/explicit-paths.rs:76:16 | LL | reuse ::foo1; | ^^ the trait `Trait` is not implemented for `S2` @@ -107,7 +89,7 @@ LL | reuse ::foo1; S error[E0308]: mismatched types - --> $DIR/explicit-paths.rs:78:30 + --> $DIR/explicit-paths.rs:76:30 | LL | reuse ::foo1; | ---------------^^^^ @@ -123,7 +105,7 @@ note: method defined here LL | fn foo1(&self, x: i32) -> i32 { x } | ^^^^ ----- -error: aborting due to 12 previous errors +error: aborting due to 10 previous errors Some errors have detailed explanations: E0119, E0277, E0308, E0407, E0425. For more information about an error, try `rustc --explain E0119`. diff --git a/tests/ui/delegation/generics/free-fn-to-free-fn-pass.rs b/tests/ui/delegation/generics/free-fn-to-free-fn-pass.rs new file mode 100644 index 0000000000000..457fc804b36d9 --- /dev/null +++ b/tests/ui/delegation/generics/free-fn-to-free-fn-pass.rs @@ -0,0 +1,160 @@ +//@ run-pass +#![feature(fn_delegation)] +#![allow(incomplete_features)] + +mod infer_types { + mod to_reuse { + pub fn foo(x: T, y: U) -> (T, U) { (x, y) } + pub fn bar(x: T) -> T { x } + } + + pub fn check_shallow_inf_vars() { + #[derive(PartialEq, Debug, Copy, Clone)] + struct T; + #[derive(PartialEq, Debug, Copy, Clone)] + struct U; + { + reuse to_reuse::foo::<_, _>; + assert_eq!(foo(T, U), (T, U)); + } + { + reuse to_reuse::foo; + assert_eq!(foo(T, U), (T, U)); + } + { + reuse to_reuse::foo::; + assert_eq!(foo(U, 0), (U, 0)); + } + } + + pub fn check_deep_inf_vars() { + #[derive(PartialEq, Debug, Copy, Clone)] + struct Us; + + #[derive(PartialEq, Debug, Copy, Clone)] + struct Ss { + x: A, + y: B, + } + let x = Ss:: { x: 0, y: [1] }; + { + reuse to_reuse::foo::, _>; + let res = foo(x, Us); + assert_eq!(res.1, Us); + assert_eq!(res.0, x); + } + { + reuse to_reuse::foo; + let res = foo(x, Us); + assert_eq!(res.1, Us); + assert_eq!(res.0, x); + } + } + + pub fn check_type_aliases() { + trait Trait { + type Type; + } + + impl Trait for u8 { + type Type = (); + } + + type Type = (); + + { + reuse to_reuse::bar::<>::Type>; + assert_eq!(bar(()), ()); + } + { + reuse to_reuse::bar::; + assert_eq!(bar(()), ()); + } + } +} + +mod infer_late_bound_regions { + mod to_reuse { + pub fn foo(x: &T) -> &T { x } + } + + pub fn check() { + let x = 1; + { + reuse to_reuse::foo; + assert_eq!(*foo(&x), 1); + } + } +} + +mod infer_early_bound_regions { + mod to_reuse { + pub fn foo<'a: 'a, T>(x: &'a T) -> &'a T { x } + } + + pub fn check_shallow_inf_vars() { + let x = 1; + { + reuse to_reuse::foo::<'_, _>; + assert_eq!(*foo(&x), 1); + } + { + reuse to_reuse::foo; + assert_eq!(*foo(&x), 1); + } + } + + pub fn check_deep_inf_vars() { + #[derive(PartialEq, Debug, Copy, Clone)] + struct S<'a, U> { + x: &'a U + } + let x = 0; + let s = S { x: &x }; + { + reuse to_reuse::foo::<'_, S<'_, i32>>; + assert_eq!(*foo(&s), s); + } + { + reuse to_reuse::foo; + assert_eq!(*foo(&s), s); + } + } +} + +mod constants { + mod to_reuse { + pub fn foo1() -> i32 { N } + pub fn foo2(x: T) -> T { x } + } + + pub fn check() { + { + reuse to_reuse::foo1::<42>; + assert_eq!(foo1(), 42); + } + + #[derive(PartialEq, Debug)] + struct S; + { + reuse to_reuse::foo2::; + let s = S; + assert_eq!(foo2(s), S::<1>); + } + { + reuse to_reuse::foo2::>; + let s = S; + assert_eq!(foo2(s), S::<2>); + } + } +} + +fn main() { + infer_types::check_shallow_inf_vars(); + infer_types::check_deep_inf_vars(); + infer_types::check_type_aliases(); + infer_late_bound_regions::check(); + infer_early_bound_regions::check_shallow_inf_vars(); + infer_early_bound_regions::check_deep_inf_vars(); + constants::check(); +} diff --git a/tests/ui/delegation/generics/free-fn-to-free-fn.rs b/tests/ui/delegation/generics/free-fn-to-free-fn.rs new file mode 100644 index 0000000000000..314d7c824bfa9 --- /dev/null +++ b/tests/ui/delegation/generics/free-fn-to-free-fn.rs @@ -0,0 +1,76 @@ +#![feature(fn_delegation)] +#![allow(incomplete_features)] + +mod infer_types { + trait Trait {} + + mod to_reuse { + use super::*; + + pub fn foo(x: T, y: U) -> (T, U) { (x, y) } + pub fn foo2(x: T) -> T { x } + } + + fn check() { + { + reuse to_reuse::foo::<_>; + //~^ ERROR function takes 2 generic arguments but 1 generic argument was supplied + //~| ERROR function takes 2 generic arguments but 1 generic argument was supplied + } + { + reuse to_reuse::foo2::; + //~^ ERROR the trait bound `u32: infer_types::Trait` is not satisfied + } + { + reuse to_reuse::foo2; + //~^ ERROR expected one of `::`, `;`, `as`, or `{`, found `<` + } + { + reuse to_reuse::foo2::; + //~^ ERROR cannot find type `T` in this scope + } + } +} + +mod infer_late_bound_regions { + mod to_reuse { + pub fn foo(x: &T) -> &T { x } + } + + fn check() { + let x = 1; + { + reuse to_reuse::foo::<'_>; + //~^ ERROR cannot specify lifetime arguments explicitly if late bound lifetime parameters are present + //~| ERROR cannot specify lifetime arguments explicitly if late bound lifetime parameters are present + assert_eq!(*foo(&x), 1); + } + } +} + +mod infer_early_bound_regions { + mod to_reuse { + pub fn foo<'a: 'a, T>(x: &'a T) -> &'a T { x } + } + + fn check() { + let x = 1; + { + reuse to_reuse::foo::<'static, _>; + assert_eq!(*foo(&x), 1); + //~^ ERROR `x` does not live long enough + } + { + fn bar<'a: 'a>(_: &'a i32) { + reuse to_reuse::foo::<'a, _>; + //~^ ERROR can't use generic parameters from outer item + } + + reuse to_reuse::foo::<'a, _>; + //~^ ERROR use of undeclared lifetime name `'a` + assert_eq!(*foo(&x), 1); + } + } +} + +fn main() {} diff --git a/tests/ui/delegation/generics/free-fn-to-free-fn.stderr b/tests/ui/delegation/generics/free-fn-to-free-fn.stderr new file mode 100644 index 0000000000000..138e92bd7d881 --- /dev/null +++ b/tests/ui/delegation/generics/free-fn-to-free-fn.stderr @@ -0,0 +1,128 @@ +error: expected one of `::`, `;`, `as`, or `{`, found `<` + --> $DIR/free-fn-to-free-fn.rs:25:33 + | +LL | reuse to_reuse::foo2; + | ^ expected one of `::`, `;`, `as`, or `{` + +error[E0401]: can't use generic parameters from outer item + --> $DIR/free-fn-to-free-fn.rs:65:39 + | +LL | fn bar<'a: 'a>(_: &'a i32) { + | -- lifetime parameter from outer item +LL | reuse to_reuse::foo::<'a, _>; + | - ^^ use of generic parameter from outer item + | | + | help: consider introducing lifetime `'a` here: `'a,` + +error[E0261]: use of undeclared lifetime name `'a` + --> $DIR/free-fn-to-free-fn.rs:69:35 + | +LL | reuse to_reuse::foo::<'a, _>; + | - ^^ undeclared lifetime + | | + | help: consider introducing lifetime `'a` here: `'a,` + +error[E0412]: cannot find type `T` in this scope + --> $DIR/free-fn-to-free-fn.rs:29:36 + | +LL | reuse to_reuse::foo2::; + | ^ not found in this scope + +error[E0107]: function takes 2 generic arguments but 1 generic argument was supplied + --> $DIR/free-fn-to-free-fn.rs:16:29 + | +LL | reuse to_reuse::foo::<_>; + | ^^^ - supplied 1 generic argument + | | + | expected 2 generic arguments + | +note: function defined here, with 2 generic parameters: `T`, `U` + --> $DIR/free-fn-to-free-fn.rs:10:16 + | +LL | pub fn foo(x: T, y: U) -> (T, U) { (x, y) } + | ^^^ - - +help: add missing generic argument + | +LL | reuse to_reuse::foo::<_, _>; + | +++ + +error[E0277]: the trait bound `u32: infer_types::Trait` is not satisfied + --> $DIR/free-fn-to-free-fn.rs:21:29 + | +LL | reuse to_reuse::foo2::; + | ^^^^ the trait `infer_types::Trait` is not implemented for `u32` + | +help: this trait has no implementations, consider adding one + --> $DIR/free-fn-to-free-fn.rs:5:5 + | +LL | trait Trait {} + | ^^^^^^^^^^^ + = help: see issue #48214 +help: add `#![feature(trivial_bounds)]` to the crate attributes to enable + | +LL + #![feature(trivial_bounds)] + | + +error[E0794]: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present + --> $DIR/free-fn-to-free-fn.rs:43:35 + | +LL | reuse to_reuse::foo::<'_>; + | ^^ + | +note: the late bound lifetime parameter is introduced here + --> $DIR/free-fn-to-free-fn.rs:37:26 + | +LL | pub fn foo(x: &T) -> &T { x } + | ^ + +error[E0107]: function takes 2 generic arguments but 1 generic argument was supplied + --> $DIR/free-fn-to-free-fn.rs:16:29 + | +LL | reuse to_reuse::foo::<_>; + | ^^^ - supplied 1 generic argument + | | + | expected 2 generic arguments + | +note: function defined here, with 2 generic parameters: `T`, `U` + --> $DIR/free-fn-to-free-fn.rs:10:16 + | +LL | pub fn foo(x: T, y: U) -> (T, U) { (x, y) } + | ^^^ - - + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` +help: add missing generic argument + | +LL | reuse to_reuse::foo::<_, _>; + | +++ + +error[E0794]: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present + --> $DIR/free-fn-to-free-fn.rs:43:35 + | +LL | reuse to_reuse::foo::<'_>; + | ^^ + | +note: the late bound lifetime parameter is introduced here + --> $DIR/free-fn-to-free-fn.rs:37:26 + | +LL | pub fn foo(x: &T) -> &T { x } + | ^ + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error[E0597]: `x` does not live long enough + --> $DIR/free-fn-to-free-fn.rs:60:29 + | +LL | let x = 1; + | - binding `x` declared here +... +LL | assert_eq!(*foo(&x), 1); + | ----^^- + | | | + | | borrowed value does not live long enough + | argument requires that `x` is borrowed for `'static` +... +LL | } + | - `x` dropped here while still borrowed + +error: aborting due to 10 previous errors + +Some errors have detailed explanations: E0107, E0261, E0277, E0401, E0412, E0597, E0794. +For more information about an error, try `rustc --explain E0107`. diff --git a/tests/ui/delegation/generics/free-fn-to-trait-methods-pass.rs b/tests/ui/delegation/generics/free-fn-to-trait-methods-pass.rs new file mode 100644 index 0000000000000..46c0072621e09 --- /dev/null +++ b/tests/ui/delegation/generics/free-fn-to-trait-methods-pass.rs @@ -0,0 +1,37 @@ +//@ run-pass +#![feature(fn_delegation)] +#![allow(incomplete_features)] + +#[derive(PartialEq, Debug, Copy, Clone)] +struct S<'a, U> { + x: &'a U +} + +trait Trait { + fn foo(&self, x: U, y: T) -> (T, U) {(y, x)} +} + +impl Trait for u8 {} + +fn check() { + { + reuse >::foo; + assert_eq!(foo(&2, "str", 1), (1, "str")); + } + { + reuse <_ as Trait<_>>::foo::<_>; + assert_eq!(foo(&2, "str", 1), (1, "str")); + } +} + +fn check_deep_inf_vars() { + let x = 0; + let s = S { x: &x }; + reuse <_ as Trait>>::foo; + assert_eq!(foo(&2, "str", s), (s, "str")); +} + +fn main() { + check(); + check_deep_inf_vars(); +} diff --git a/tests/ui/delegation/generics/free-fn-to-trait-methods.rs b/tests/ui/delegation/generics/free-fn-to-trait-methods.rs new file mode 100644 index 0000000000000..43e9927c80bbb --- /dev/null +++ b/tests/ui/delegation/generics/free-fn-to-trait-methods.rs @@ -0,0 +1,33 @@ +#![feature(fn_delegation)] +#![allow(incomplete_features)] + +trait Marker {} + +trait Trait { + fn foo(&self, x: U, y: T) -> (T, U) {(y, x)} + fn bar(&self, x: U) {} +} + +impl Trait for u8 {} +impl Marker for u8 {} + +fn main() { + { + reuse >::foo; + foo(&2, "str", 1); + //~^ ERROR the trait bound `u16: Trait<_>` is not satisfied + } + { + reuse ::foo; + //~^ ERROR missing generics for trait `Trait` + //~| ERROR missing generics for trait `Trait` + } + { + reuse Trait::<_>::bar::; + //~^ ERROR the trait bound `u16: Marker` is not satisfied + } + { + reuse >::bar; + //~^ ERROR the trait bound `u16: Marker` is not satisfied + } +} diff --git a/tests/ui/delegation/generics/free-fn-to-trait-methods.stderr b/tests/ui/delegation/generics/free-fn-to-trait-methods.stderr new file mode 100644 index 0000000000000..39d296d1ecb40 --- /dev/null +++ b/tests/ui/delegation/generics/free-fn-to-trait-methods.stderr @@ -0,0 +1,79 @@ +error[E0107]: missing generics for trait `Trait` + --> $DIR/free-fn-to-trait-methods.rs:21:23 + | +LL | reuse ::foo; + | ^^^^^ expected 1 generic argument + | +note: trait defined here, with 1 generic parameter: `T` + --> $DIR/free-fn-to-trait-methods.rs:6:7 + | +LL | trait Trait { + | ^^^^^ - +help: add missing generic argument + | +LL | reuse >::foo; + | +++ + +error[E0277]: the trait bound `u16: Marker` is not satisfied + --> $DIR/free-fn-to-trait-methods.rs:26:27 + | +LL | reuse Trait::<_>::bar::; + | ^^^ the trait `Marker` is not implemented for `u16` + | + = help: the trait `Marker` is implemented for `u8` + = help: see issue #48214 +help: add `#![feature(trivial_bounds)]` to the crate attributes to enable + | +LL + #![feature(trivial_bounds)] + | + +error[E0277]: the trait bound `u16: Marker` is not satisfied + --> $DIR/free-fn-to-trait-methods.rs:30:35 + | +LL | reuse >::bar; + | ^^^ the trait `Marker` is not implemented for `u16` + | + = help: the trait `Marker` is implemented for `u8` + = help: see issue #48214 +help: add `#![feature(trivial_bounds)]` to the crate attributes to enable + | +LL + #![feature(trivial_bounds)] + | + +error[E0277]: the trait bound `u16: Trait<_>` is not satisfied + --> $DIR/free-fn-to-trait-methods.rs:17:24 + | +LL | foo(&2, "str", 1); + | --- ^ the trait `Trait<_>` is not implemented for `u16` + | | + | required by a bound introduced by this call + | + = help: the trait `Trait<_>` is implemented for `u8` + = help: for that trait implementation, expected `u8`, found `u16` +note: required by a bound in `main::foo` + --> $DIR/free-fn-to-trait-methods.rs:16:34 + | +LL | reuse >::foo; + | ^^^ required by this bound in `foo` + +error[E0107]: missing generics for trait `Trait` + --> $DIR/free-fn-to-trait-methods.rs:21:23 + | +LL | reuse ::foo; + | ^^^^^ expected 1 generic argument + | +note: trait defined here, with 1 generic parameter: `T` + --> $DIR/free-fn-to-trait-methods.rs:6:7 + | +LL | trait Trait { + | ^^^^^ - + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` +help: add missing generic argument + | +LL | reuse >::foo; + | +++ + +error: aborting due to 5 previous errors + +Some errors have detailed explanations: E0107, E0277. +For more information about an error, try `rustc --explain E0107`. diff --git a/tests/ui/delegation/not-supported.rs b/tests/ui/delegation/not-supported.rs index 5f78de97638b5..8a94fe35b395f 100644 --- a/tests/ui/delegation/not-supported.rs +++ b/tests/ui/delegation/not-supported.rs @@ -14,9 +14,9 @@ mod generics { fn foo3<'a: 'a>(_: &'a u32) {} reuse GenericTrait::bar; - //~^ ERROR delegation with early bound generics is not supported yet + //~^ ERROR early bound generics are not supported for associated delegation items reuse GenericTrait::bar1; - //~^ ERROR delegation with early bound generics is not supported yet + //~^ ERROR early bound generics are not supported for associated delegation items } struct F; @@ -27,37 +27,37 @@ mod generics { impl GenericTrait for S { reuse >::bar { &self.0 } - //~^ ERROR delegation with early bound generics is not supported yet + //~^ ERROR early bound generics are not supported for associated delegation items reuse GenericTrait::::bar1; - //~^ ERROR delegation with early bound generics is not supported yet + //~^ ERROR early bound generics are not supported for associated delegation items } impl GenericTrait<()> for () { reuse GenericTrait::bar { &F } - //~^ ERROR delegation with early bound generics is not supported yet + //~^ ERROR early bound generics are not supported for associated delegation items reuse GenericTrait::bar1; - //~^ ERROR delegation with early bound generics is not supported yet + //~^ ERROR early bound generics are not supported for associated delegation items } impl Trait for &S { reuse Trait::foo; - //~^ ERROR delegation with early bound generics is not supported yet + //~^ 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 delegation with early bound generics is not supported yet + //~^ 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 delegation with early bound generics is not supported yet + //~^ ERROR early bound generics are not supported for associated delegation items //~| ERROR lifetime parameters or bounds on method `foo3` do not match the trait declaration } struct GenericS(T); impl Trait for GenericS { reuse Trait::foo { &self.0 } - //~^ ERROR delegation with early bound generics is not supported yet + //~^ ERROR early bound generics are not supported for associated delegation items } } @@ -72,7 +72,6 @@ mod opaque { pub fn opaque_ret() -> impl Trait { unimplemented!() } } reuse to_reuse::opaque_arg; - //~^ ERROR delegation with early bound generics is not supported yet trait ToReuse { fn opaque_ret() -> impl Trait { unimplemented!() } diff --git a/tests/ui/delegation/not-supported.stderr b/tests/ui/delegation/not-supported.stderr index e2cb04f977b1e..73712584e9e7f 100644 --- a/tests/ui/delegation/not-supported.stderr +++ b/tests/ui/delegation/not-supported.stderr @@ -1,4 +1,4 @@ -error: delegation with early bound generics is not supported yet +error: early bound generics are not supported for associated delegation items --> $DIR/not-supported.rs:16:29 | LL | fn bar(&self, x: T) -> T { x } @@ -7,7 +7,7 @@ LL | fn bar(&self, x: T) -> T { x } LL | reuse GenericTrait::bar; | ^^^ -error: delegation with early bound generics is not supported yet +error: early bound generics are not supported for associated delegation items --> $DIR/not-supported.rs:18:29 | LL | fn bar1() {} @@ -16,7 +16,7 @@ LL | fn bar1() {} LL | reuse GenericTrait::bar1; | ^^^^ -error: delegation with early bound generics is not supported yet +error: early bound generics are not supported for associated delegation items --> $DIR/not-supported.rs:29:39 | LL | fn bar(&self, x: T) -> T { x } @@ -25,7 +25,7 @@ LL | fn bar(&self, x: T) -> T { x } LL | reuse >::bar { &self.0 } | ^^^ -error: delegation with early bound generics is not supported yet +error: early bound generics are not supported for associated delegation items --> $DIR/not-supported.rs:31:34 | LL | fn bar1() {} @@ -34,7 +34,7 @@ LL | fn bar1() {} LL | reuse GenericTrait::::bar1; | ^^^^ -error: delegation with early bound generics is not supported yet +error: early bound generics are not supported for associated delegation items --> $DIR/not-supported.rs:36:29 | LL | fn bar(&self, x: T) -> T { x } @@ -43,7 +43,7 @@ LL | fn bar(&self, x: T) -> T { x } LL | reuse GenericTrait::bar { &F } | ^^^ -error: delegation with early bound generics is not supported yet +error: early bound generics are not supported for associated delegation items --> $DIR/not-supported.rs:38:29 | LL | fn bar1() {} @@ -52,7 +52,7 @@ LL | fn bar1() {} LL | reuse GenericTrait::bar1; | ^^^^ -error: delegation with early bound generics is not supported yet +error: early bound generics are not supported for associated delegation items --> $DIR/not-supported.rs:43:22 | LL | fn foo(&self, x: i32) -> i32 { x } @@ -61,6 +61,15 @@ LL | fn foo(&self, x: i32) -> i32 { x } LL | reuse Trait::foo; | ^^^ +error: early bound generics are not supported for associated delegation items + --> $DIR/not-supported.rs:49:22 + | +LL | fn foo2(&self, x: T) -> T { x } + | ---------------------------- callee defined here +... +LL | reuse Trait::foo2 { &self.0 } + | ^^^^ + error[E0049]: method `foo2` has 0 type parameters but its trait declaration has 1 type parameter --> $DIR/not-supported.rs:49:22 | @@ -70,7 +79,7 @@ LL | fn foo2(&self, x: T) -> T { x } LL | reuse Trait::foo2 { &self.0 } | ^^^^ found 0 type parameters -error: delegation with early bound generics is not supported yet +error: early bound generics are not supported for associated delegation items --> $DIR/not-supported.rs:52:29 | LL | fn foo3<'a: 'a>(_: &'a u32) {} @@ -88,81 +97,63 @@ LL | fn foo3<'a: 'a>(_: &'a u32) {} LL | reuse ::foo3; | ^^^^ lifetimes do not match method in trait -error: delegation with early bound generics is not supported yet - --> $DIR/not-supported.rs:59:22 +error: recursive delegation is not supported yet + --> $DIR/not-supported.rs:98:22 | -LL | fn foo(&self, x: i32) -> i32 { x } - | ---------------------------- callee defined here +LL | pub reuse to_reuse2::foo; + | --- callee defined here ... -LL | reuse Trait::foo { &self.0 } +LL | reuse to_reuse1::foo; | ^^^ -error: delegation with early bound generics is not supported yet - --> $DIR/not-supported.rs:49:22 +error: early bound generics are not supported for associated delegation items + --> $DIR/not-supported.rs:59:22 | -LL | fn foo2(&self, x: T) -> T { x } +LL | fn foo(&self, x: i32) -> i32 { x } | ---------------------------- callee defined here ... -LL | reuse Trait::foo2 { &self.0 } - | ^^^^ - -error: delegation with early bound generics is not supported yet - --> $DIR/not-supported.rs:74:21 - | -LL | pub fn opaque_arg(_: impl Trait) -> i32 { 0 } - | --------------------------------------- callee defined here -... -LL | reuse to_reuse::opaque_arg; - | ^^^^^^^^^^ +LL | reuse Trait::foo { &self.0 } + | ^^^ -error[E0391]: cycle detected when computing type of `opaque::::{synthetic#0}` - --> $DIR/not-supported.rs:83:25 +error[E0391]: cycle detected when computing type of `opaque::::{synthetic#0}` + --> $DIR/not-supported.rs:82: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:83:25 + --> $DIR/not-supported.rs:82: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:82: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/not-supported.rs:81: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 -error[E0391]: cycle detected when computing type of `opaque::::{synthetic#0}` - --> $DIR/not-supported.rs:86:24 +error[E0391]: cycle detected when computing type of `opaque::::{synthetic#0}` + --> $DIR/not-supported.rs:85: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:86:24 + --> $DIR/not-supported.rs:85: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: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/not-supported.rs:84: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:99:22 - | -LL | pub reuse to_reuse2::foo; - | --- callee defined here -... -LL | reuse to_reuse1::foo; - | ^^^ - -error: aborting due to 16 previous errors +error: aborting due to 15 previous errors Some errors have detailed explanations: E0049, E0195, E0391. For more information about an error, try `rustc --explain E0049`. diff --git a/tests/ui/delegation/target-expr.rs b/tests/ui/delegation/target-expr.rs index fd7ea943b9d5e..f766ca7356a4c 100644 --- a/tests/ui/delegation/target-expr.rs +++ b/tests/ui/delegation/target-expr.rs @@ -14,9 +14,7 @@ fn foo(x: i32) -> i32 { x } fn bar(_: T) { reuse Trait::static_method { - //~^ ERROR delegation to a trait method from a free function is not supported yet - //~| ERROR delegation with early bound generics is not supported yet - //~| ERROR mismatched types + //~^ ERROR mismatched types let _ = T::Default(); //~^ ERROR can't use generic parameters from outer item } @@ -25,7 +23,6 @@ fn bar(_: T) { fn main() { let y = 0; reuse ::static_method { - //~^ ERROR delegation to a trait method from a free function is not supported yet let x = y; //~^ ERROR can't capture dynamic environment in a fn item foo(self); diff --git a/tests/ui/delegation/target-expr.stderr b/tests/ui/delegation/target-expr.stderr index b30f0c474c68b..f5556bf9f4514 100644 --- a/tests/ui/delegation/target-expr.stderr +++ b/tests/ui/delegation/target-expr.stderr @@ -1,16 +1,16 @@ error[E0401]: can't use generic parameters from outer item - --> $DIR/target-expr.rs:20:17 + --> $DIR/target-expr.rs:18:17 | LL | fn bar(_: T) { | - type parameter from outer item LL | reuse Trait::static_method { | - help: try introducing a local generic parameter here: `T,` -... +LL | LL | let _ = T::Default(); | ^^^^^^^^^^ use of generic parameter from outer item error[E0434]: can't capture dynamic environment in a fn item - --> $DIR/target-expr.rs:29:17 + --> $DIR/target-expr.rs:26:17 | LL | let x = y; | ^ @@ -18,7 +18,7 @@ LL | let x = y; = help: use the `|| { ... }` closure form instead error[E0424]: expected value, found module `self` - --> $DIR/target-expr.rs:36:5 + --> $DIR/target-expr.rs:33:5 | LL | fn main() { | ---- this function can't have a `self` parameter @@ -27,58 +27,29 @@ LL | self.0; | ^^^^ `self` value is a keyword only available in methods with a `self` parameter error[E0425]: cannot find value `x` in this scope - --> $DIR/target-expr.rs:38:13 + --> $DIR/target-expr.rs:35:13 | LL | let z = x; | ^ | help: the binding `x` is available in a different scope in the same function - --> $DIR/target-expr.rs:29:13 + --> $DIR/target-expr.rs:26:13 | LL | let x = y; | ^ -error: delegation with early bound generics is not supported yet - --> $DIR/target-expr.rs:16:18 - | -LL | fn static_method(x: i32) -> i32 { x } - | ------------------------------- callee defined here -... -LL | reuse Trait::static_method { - | ^^^^^^^^^^^^^ - -error: delegation to a trait method from a free function is not supported yet - --> $DIR/target-expr.rs:16:18 - | -LL | fn static_method(x: i32) -> i32 { x } - | ------------------------------- callee defined here -... -LL | reuse Trait::static_method { - | ^^^^^^^^^^^^^ - -error: delegation to a trait method from a free function is not supported yet - --> $DIR/target-expr.rs:27:25 - | -LL | fn static_method(x: i32) -> i32 { x } - | ------------------------------- callee defined here -... -LL | reuse ::static_method { - | ^^^^^^^^^^^^^ - error[E0308]: mismatched types --> $DIR/target-expr.rs:16:32 | LL | reuse Trait::static_method { | ________________________________^ LL | | -LL | | -LL | | LL | | let _ = T::Default(); LL | | LL | | } | |_____^ expected `i32`, found `()` -error: aborting due to 8 previous errors +error: aborting due to 5 previous errors Some errors have detailed explanations: E0308, E0401, E0424, E0425, E0434. For more information about an error, try `rustc --explain E0308`.