diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 1c4c5728b04a4..01503f05f0ca2 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -3003,10 +3003,11 @@ pub struct Fn { #[derive(Clone, Encodable, Decodable, Debug)] pub struct Delegation { + /// Path resolution id. pub id: NodeId, - pub path: (Option>, Path), - pub target_expr: Option>, - pub span: Span, + pub qself: Option>, + pub path: Path, + pub body: Option>, } #[derive(Clone, Encodable, Decodable, Debug)] @@ -3131,7 +3132,7 @@ impl ItemKind { ItemKind::MacCall(..) => "item macro invocation", ItemKind::MacroDef(..) => "macro definition", ItemKind::Impl { .. } => "implementation", - ItemKind::Delegation(..) => "delegation", + ItemKind::Delegation(..) => "delegated function", } } diff --git a/compiler/rustc_ast/src/ast_traits.rs b/compiler/rustc_ast/src/ast_traits.rs index 2b5377c3457dd..4dc9c30a2c807 100644 --- a/compiler/rustc_ast/src/ast_traits.rs +++ b/compiler/rustc_ast/src/ast_traits.rs @@ -5,7 +5,7 @@ use crate::ptr::P; use crate::token::Nonterminal; use crate::tokenstream::LazyAttrTokenStream; -use crate::{Arm, Crate, Delegation, ExprField, FieldDef, GenericParam, Param, PatField, Variant}; +use crate::{Arm, Crate, ExprField, FieldDef, GenericParam, Param, PatField, Variant}; use crate::{AssocItem, Expr, ForeignItem, Item, NodeId}; use crate::{AttrItem, AttrKind, Block, Pat, Path, Ty, Visibility}; use crate::{AttrVec, Attribute, Stmt, StmtKind}; @@ -80,7 +80,6 @@ impl_has_node_id!( Stmt, Ty, Variant, - Delegation ); impl> HasNodeId for T { @@ -109,19 +108,7 @@ macro_rules! impl_has_span { }; } -impl_has_span!( - AssocItem, - Block, - Expr, - ForeignItem, - Item, - Pat, - Path, - Stmt, - Ty, - Visibility, - Delegation -); +impl_has_span!(AssocItem, Block, Expr, ForeignItem, Item, Pat, Path, Stmt, Ty, Visibility); impl> HasSpan for T { fn span(&self) -> Span { @@ -172,7 +159,7 @@ macro_rules! impl_has_tokens_none { } impl_has_tokens!(AssocItem, AttrItem, Block, Expr, ForeignItem, Item, Pat, Path, Ty, Visibility); -impl_has_tokens_none!(Arm, ExprField, FieldDef, GenericParam, Param, PatField, Variant, Delegation); +impl_has_tokens_none!(Arm, ExprField, FieldDef, GenericParam, Param, PatField, Variant); impl> HasTokens for T { fn tokens(&self) -> Option<&LazyAttrTokenStream> { diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs index d16c2ee7aa1bf..c491fded88f72 100644 --- a/compiler/rustc_ast/src/mut_visit.rs +++ b/compiler/rustc_ast/src/mut_visit.rs @@ -1119,10 +1119,10 @@ pub fn noop_visit_item_kind(kind: &mut ItemKind, vis: &mut T) { ItemKind::MacroDef(def) => vis.visit_macro_def(def), ItemKind::Delegation(box delegation) => { vis.visit_id(&mut delegation.id); - vis.visit_qself(&mut delegation.path.0); - vis.visit_path(&mut delegation.path.1); - if let Some(target_expr) = &mut delegation.target_expr { - vis.visit_expr(target_expr); + vis.visit_qself(&mut delegation.qself); + vis.visit_path(&mut delegation.path); + if let Some(body) = &mut delegation.body { + vis.visit_block(body); } } } @@ -1165,10 +1165,10 @@ pub fn noop_flat_map_assoc_item( AssocItemKind::MacCall(mac) => visitor.visit_mac_call(mac), AssocItemKind::Delegation(box delegation) => { visitor.visit_id(&mut delegation.id); - visitor.visit_qself(&mut delegation.path.0); - visitor.visit_path(&mut delegation.path.1); - if let Some(target_expr) = &mut delegation.target_expr { - visitor.visit_expr(target_expr); + visitor.visit_qself(&mut delegation.qself); + visitor.visit_path(&mut delegation.path); + if let Some(body) = &mut delegation.body { + visitor.visit_block(body); } } } diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index 2fca9724bbac3..eb0c1c67f0f6f 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -376,12 +376,12 @@ pub fn walk_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a Item) { ItemKind::MacCall(mac) => visitor.visit_mac_call(mac), ItemKind::MacroDef(ts) => visitor.visit_mac_def(ts, item.id), ItemKind::Delegation(box delegation) => { - if let Some(qself) = &delegation.path.0 { + if let Some(qself) = &delegation.qself { visitor.visit_ty(&qself.ty); } - walk_path(visitor, &delegation.path.1); - if let Some(target_expr) = &delegation.target_expr { - visitor.visit_expr(target_expr); + walk_path(visitor, &delegation.path); + if let Some(body) = &delegation.body { + visitor.visit_block(body); } } } @@ -714,12 +714,12 @@ pub fn walk_assoc_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a AssocItem, visitor.visit_mac_call(mac); } AssocItemKind::Delegation(box delegation) => { - if let Some(qself) = &delegation.path.0 { + if let Some(qself) = &delegation.qself { visitor.visit_ty(&qself.ty); } - walk_path(visitor, &delegation.path.1); - if let Some(target_expr) = &delegation.target_expr { - visitor.visit_expr(target_expr); + walk_path(visitor, &delegation.path); + if let Some(body) = &delegation.body { + visitor.visit_block(body); } } } diff --git a/compiler/rustc_ast_lowering/src/delegation.rs b/compiler/rustc_ast_lowering/src/delegation.rs index 97b0792e9e529..cc907fbcb6552 100644 --- a/compiler/rustc_ast_lowering/src/delegation.rs +++ b/compiler/rustc_ast_lowering/src/delegation.rs @@ -3,8 +3,7 @@ use crate::{ImplTraitPosition, ResolverAstLoweringExt}; use super::{ImplTraitContext, LoweringContext, ParamMode}; use ast::visit::Visitor; -use hir::def::DefKind; -use hir::def::PartialRes; +use hir::def::{DefKind, PartialRes, Res}; use hir::{BodyId, HirId}; use rustc_ast as ast; use rustc_ast::*; @@ -24,13 +23,9 @@ pub struct DelegationResults<'hir> { } impl<'hir> LoweringContext<'_, 'hir> { - pub fn delegation_has_self(&self, delegation: &Delegation) -> bool { - let res_id = self.get_delegation_res_id(delegation.id); + pub fn delegation_has_self(&self, node_id: NodeId, span: Span) -> bool { + let res_id = self.get_delegation_res_id(node_id, span); let Some(res_id) = res_id else { - self.tcx.sess.span_delayed_bug( - delegation.span, - "LoweringContext: couldn't resolve delegation item", - ); return false; }; @@ -40,37 +35,50 @@ impl<'hir> LoweringContext<'_, 'hir> { match self.tcx.def_kind(res_id) { DefKind::Fn => false, DefKind::AssocFn => self.tcx.associated_item(res_id).fn_has_self_parameter, - _ => span_bug!(delegation.span, "unexpected DefKind for delegation item"), + _ => span_bug!(span, "unexpected DefKind for delegation item"), } } } - pub fn lower_delegation(&mut self, delegation: &Delegation) -> DelegationResults<'hir> { - let res_id = self.get_delegation_res_id(delegation.id); + pub fn lower_delegation( + &mut self, + delegation: &Delegation, + node_id: NodeId, + span: Span, + ) -> DelegationResults<'hir> { + let res_id = self.get_delegation_res_id(node_id, span); let Some(res_id) = res_id else { - self.tcx.sess.span_delayed_bug( - delegation.span, - "LoweringContext: couldn't resolve delegation item", - ); - return self.generate_delegation_error(delegation); + return self.generate_delegation_error(span); }; - let decl = self.lower_delegation_decl(res_id, delegation.span); - let sig = self.lower_delegation_sig(delegation.span, decl); - let body_id = self.lower_delegation_body(sig.decl, delegation); + let decl = self.lower_delegation_decl(res_id, span); + let sig = self.lower_delegation_sig(span, decl); + let body_id = self.lower_delegation_body(sig.decl, delegation, node_id, span); - let generics = self.lower_delegation_generics(delegation.span); + let generics = self.lower_delegation_generics(span); DelegationResults { body_id, sig, generics } } - fn get_delegation_res_id(&self, node_id: NodeId) -> Option { - self.resolver.get_partial_res(node_id).map(|r| r.base_res().opt_def_id()).unwrap_or(None) + fn get_delegation_res_id(&self, node_id: NodeId, span: Span) -> Option { + let res = self + .resolver + .get_partial_res(node_id) + .map(|or| or.full_res().map(|r| r.opt_def_id()).unwrap_or(None)) + .unwrap_or(None); + + if res.is_none() { + self.tcx + .sess + .span_delayed_bug(span, "LoweringContext: couldn't resolve delegation item"); + } + + res } fn lower_delegation_generics(&mut self, span: Span) -> &'hir hir::Generics<'hir> { self.arena.alloc(hir::Generics { - params: self.arena.alloc_from_iter([]), - predicates: self.arena.alloc_from_iter([]), + params: &[], + predicates: &[], has_where_clause_predicates: false, where_clause_span: span, span, @@ -78,20 +86,22 @@ impl<'hir> LoweringContext<'_, 'hir> { } fn lower_delegation_decl(&mut self, res_id: DefId, span: Span) -> &'hir hir::FnDecl<'hir> { - let args_count = if res_id.is_local() { - self.resolver.fns_arguments_count[&res_id] + let args_count = if let Some(local_res_id) = res_id.as_local() { + // Map may be filled incorrectly due to recursive delegation. + // Error will be emmited later in astconv. + self.resolver.fn_parameter_counts.get(&local_res_id).cloned().unwrap_or_default() } else { self.tcx.fn_arg_names(res_id).len() }; let inputs = self.arena.alloc_from_iter((0..args_count).into_iter().map(|arg| hir::Ty { hir_id: self.next_id(), - kind: hir::TyKind::InferDelegation(res_id, hir::InferDelegationVar::Input(arg)), + kind: hir::TyKind::InferDelegation(res_id, hir::InferDelegationKind::Input(arg)), span, })); let output = self.arena.alloc(hir::Ty { hir_id: self.next_id(), - kind: hir::TyKind::InferDelegation(res_id, hir::InferDelegationVar::Output), + kind: hir::TyKind::InferDelegation(res_id, hir::InferDelegationKind::Output), span, }); @@ -138,16 +148,13 @@ impl<'hir> LoweringContext<'_, 'hir> { let segments = self.arena.alloc_from_iter(iter::once(hir::PathSegment { ident: Ident::empty(), hir_id: self.next_id(), - res: hir::def::Res::Local(param_id), + res: Res::Local(param_id), args: None, infer_args: false, })); - let path = self.arena.alloc(hir::Path { - span: ty.span, - res: hir::def::Res::Local(param_id), - segments, - }); + let path = + self.arena.alloc(hir::Path { span: ty.span, res: Res::Local(param_id), segments }); hir::Expr { hir_id: self.next_id(), @@ -160,17 +167,19 @@ impl<'hir> LoweringContext<'_, 'hir> { &mut self, decl: &'hir hir::FnDecl<'hir>, delegation: &Delegation, + node_id: NodeId, + span: Span, ) -> BodyId { - let (qself, path) = &delegation.path; + let path_id = if self.is_in_trait_impl { delegation.id } else { node_id }; let path = self.lower_qpath( - delegation.id, - qself, - path, + path_id, + &delegation.qself, + &delegation.path, ParamMode::Optional, &ImplTraitContext::Disallowed(ImplTraitPosition::Path), None, ); - let expr = delegation.target_expr.as_deref(); + let block = delegation.body.as_deref(); self.lower_body(|this| { let mut parameters: Vec> = Vec::new(); @@ -180,18 +189,26 @@ impl<'hir> LoweringContext<'_, 'hir> { let (param, pat_node_id) = this.generate_param(param_ty); parameters.push(param); - if idx != 0 || expr.is_none() { - let pat_hir_id = this.lower_node_id(pat_node_id); - let arg = this.generate_arg(param_ty, pat_hir_id); - args.push(arg); + let arg = if let Some(block) = block + && idx == 0 + { + let mut self_resolver = SelfResolver { + resolver: this.resolver, + delegation_id: delegation.id, + self_param_id: pat_node_id, + }; + self_resolver.visit_block(block); + let block = this.lower_block(block, false); + hir::Expr { + hir_id: this.next_id(), + kind: hir::ExprKind::Block(block, None), + span, + } } else { - let expr = expr.unwrap(); - let mut self_resolver = - SelfResolver { res_id: pat_node_id, resolver: this.resolver }; - self_resolver.visit_expr(expr); - let target_expr = this.lower_expr_mut(expr); - args.push(target_expr); + let pat_hir_id = this.lower_node_id(pat_node_id); + this.generate_arg(param_ty, pat_hir_id) }; + args.push(arg); } let args = self.arena.alloc_from_iter(args); @@ -218,7 +235,7 @@ impl<'hir> LoweringContext<'_, 'hir> { }); let block = self.arena.alloc(hir::Block { - stmts: self.arena.alloc_from_iter([]), + stmts: &[], expr: Some(expr), hir_id: self.next_id(), rules: hir::BlockCheckMode::DefaultBlock, @@ -233,29 +250,25 @@ impl<'hir> LoweringContext<'_, 'hir> { } } - fn generate_delegation_error(&mut self, delegation: &Delegation) -> DelegationResults<'hir> { - let generics = self.lower_delegation_generics(delegation.span); + fn generate_delegation_error(&mut self, span: Span) -> DelegationResults<'hir> { + let generics = self.lower_delegation_generics(span); let decl = self.arena.alloc(hir::FnDecl { - inputs: self.arena.alloc_from_iter([]), - output: hir::FnRetTy::DefaultReturn(delegation.span), + inputs: &[], + output: hir::FnRetTy::DefaultReturn(span), c_variadic: false, lifetime_elision_allowed: true, implicit_self: hir::ImplicitSelfKind::None, }); - let sig = self.lower_delegation_sig(delegation.span, decl); + let sig = self.lower_delegation_sig(span, decl); let body_id = self.lower_body(|this| { - let err = this.tcx.sess.span_delayed_bug( - delegation.span, - "LoweringContext: couldn't resolve delegation item", - ); - let expr = hir::Expr { - hir_id: this.next_id(), - kind: hir::ExprKind::Err(err), - span: delegation.span, - }; - (this.arena.alloc_from_iter([]), expr) + let err = this + .tcx + .sess + .span_delayed_bug(span, "LoweringContext: couldn't resolve delegation item"); + let expr = hir::Expr { hir_id: this.next_id(), kind: hir::ExprKind::Err(err), span }; + (&[], expr) }); DelegationResults { generics, body_id, sig } } @@ -263,15 +276,31 @@ impl<'hir> LoweringContext<'_, 'hir> { struct SelfResolver<'a> { resolver: &'a mut ResolverAstLowering, - res_id: NodeId, + delegation_id: NodeId, + self_param_id: NodeId, +} + +impl<'a> SelfResolver<'a> { + fn try_replace_id(&mut self, id: NodeId) { + if let Some(res) = self.resolver.partial_res_map.get(&id) + && let Some(Res::Local(res_id)) = res.full_res() + && res_id == self.delegation_id + { + let new_res = PartialRes::new(Res::Local(self.self_param_id)); + self.resolver.partial_res_map.insert(id, new_res); + } + } } -impl<'ast, 'a> ast::visit::Visitor<'ast> for SelfResolver<'a> { +impl<'ast, 'a> Visitor<'ast> for SelfResolver<'a> { fn visit_path(&mut self, path: &'ast Path, id: NodeId) { - if path.segments.len() == 1 && path.segments[0].ident.name == kw::SelfLower { - let res = PartialRes::new(hir::def::Res::Local(self.res_id)); - self.resolver.partial_res_map.insert(id, res); - self.resolver.partial_res_map.insert(path.segments[0].id, res); + self.try_replace_id(id); + visit::walk_path(self, path); + } + + fn visit_path_segment(&mut self, path_segment: &'ast PathSegment) { + if kw::SelfLower == path_segment.ident.name { + self.try_replace_id(path_segment.id); } } } diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index d7dd58dc6671f..4d24b3eb9899c 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -432,16 +432,14 @@ impl<'hir> LoweringContext<'_, 'hir> { let macro_def = self.arena.alloc(ast::MacroDef { body, macro_rules: *macro_rules }); hir::ItemKind::Macro(macro_def, macro_kind) } - ItemKind::Delegation(box delegation) => self.with_new_scopes(ident.span, |this| { - this.current_item = Some(ident.span); - - let delegation_results = this.lower_delegation(delegation); + ItemKind::Delegation(box delegation) => { + let delegation_results = self.lower_delegation(delegation, id, span); hir::ItemKind::Fn( delegation_results.sig, delegation_results.generics, delegation_results.body_id, ) - }), + } ItemKind::MacCall(..) => { panic!("`TyMac` should have been expanded by now") } @@ -803,15 +801,12 @@ impl<'hir> LoweringContext<'_, 'hir> { (generics, kind, ty.is_some()) } AssocItemKind::Delegation(box delegation) => { - let delegation_results = self.lower_delegation(delegation); - ( - delegation_results.generics, - hir::TraitItemKind::Fn( - delegation_results.sig, - hir::TraitFn::Provided(delegation_results.body_id), - ), - true, - ) + let delegation_results = self.lower_delegation(delegation, i.id, i.span); + let item_kind = hir::TraitItemKind::Fn( + delegation_results.sig, + hir::TraitFn::Provided(delegation_results.body_id), + ); + (delegation_results.generics, item_kind, true) } AssocItemKind::MacCall(..) => panic!("macro item shouldn't exist at this point"), }; @@ -834,8 +829,8 @@ impl<'hir> LoweringContext<'_, 'hir> { AssocItemKind::Fn(box Fn { sig, .. }) => { hir::AssocItemKind::Fn { has_self: sig.decl.has_self() } } - AssocItemKind::Delegation(box delegation) => { - hir::AssocItemKind::Fn { has_self: self.delegation_has_self(delegation) } + AssocItemKind::Delegation(..) => { + hir::AssocItemKind::Fn { has_self: self.delegation_has_self(i.id, i.span) } } AssocItemKind::MacCall(..) => unimplemented!(), }; @@ -920,7 +915,7 @@ impl<'hir> LoweringContext<'_, 'hir> { ) } AssocItemKind::Delegation(box delegation) => { - let delegation_results = self.lower_delegation(delegation); + let delegation_results = self.lower_delegation(delegation, i.id, i.span); ( delegation_results.generics, hir::ImplItemKind::Fn(delegation_results.sig, delegation_results.body_id), @@ -952,15 +947,16 @@ impl<'hir> LoweringContext<'_, 'hir> { AssocItemKind::Fn(box Fn { sig, .. }) => { hir::AssocItemKind::Fn { has_self: sig.decl.has_self() } } - AssocItemKind::Delegation(box delegation) => { - hir::AssocItemKind::Fn { has_self: self.delegation_has_self(delegation) } + AssocItemKind::Delegation(..) => { + hir::AssocItemKind::Fn { has_self: self.delegation_has_self(i.id, i.span) } } AssocItemKind::MacCall(..) => unimplemented!(), }, trait_item_def_id: self .resolver .get_partial_res(i.id) - .map(|r| r.expect_full_res().def_id()), + .map(|or| or.full_res().map(|r| r.opt_def_id()).unwrap_or(None)) + .unwrap_or(None), } } diff --git a/compiler/rustc_ast_pretty/src/pprust/state/item.rs b/compiler/rustc_ast_pretty/src/pprust/state/item.rs index e22759ae31364..18a39a703d4da 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state/item.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state/item.rs @@ -574,7 +574,7 @@ impl<'a> State<'a> { pub(crate) fn print_delegation(&mut self, delegation: &ast::Delegation) { self.ibox(0); self.word_space("reuse"); - let (qself, path, expr) = (&delegation.path.0, &delegation.path.1, &delegation.target_expr); + let (qself, path, body) = (&delegation.qself, &delegation.path, &delegation.body); if let Some(qself) = qself { self.print_qpath(path, qself.ast_deref(), false); @@ -582,9 +582,9 @@ impl<'a> State<'a> { self.print_path(path, false, 0); } self.space(); - if let Some(target_expr) = expr { + if let Some(body) = body { self.word_space("{"); - self.print_expr(target_expr.ast_deref(), FixupContext::default()); + self.print_block(body.ast_deref()); self.word(" }"); } else { self.word(";"); diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 58126340e2d77..c7f69164ab26b 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -2522,7 +2522,7 @@ pub enum OpaqueTyOrigin { } #[derive(Debug, Clone, Copy, PartialEq, Eq, HashStable_Generic)] -pub enum InferDelegationVar { +pub enum InferDelegationKind { Input(usize), Output, } @@ -2530,7 +2530,8 @@ pub enum InferDelegationVar { /// The various kinds of types recognized by the compiler. #[derive(Debug, Clone, Copy, HashStable_Generic)] pub enum TyKind<'hir> { - InferDelegation(DefId, InferDelegationVar), + /// Actual type should be inherited from `DefId` signature + InferDelegation(DefId, InferDelegationKind), /// A variable length slice (i.e., `[T]`). Slice(&'hir Ty<'hir>), /// A fixed length array (i.e., `[T; n]`). diff --git a/compiler/rustc_hir_analysis/messages.ftl b/compiler/rustc_hir_analysis/messages.ftl index 348cdfb0a291b..35798b7618bbc 100644 --- a/compiler/rustc_hir_analysis/messages.ftl +++ b/compiler/rustc_hir_analysis/messages.ftl @@ -264,7 +264,7 @@ 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 = - delegation with {$descr} is not supported yet + {$descr} is not supported yet .label = callee defined here 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/astconv/mod.rs b/compiler/rustc_hir_analysis/src/astconv/mod.rs index 4d0ac9d46a87d..2cd5642abd17d 100644 --- a/compiler/rustc_hir_analysis/src/astconv/mod.rs +++ b/compiler/rustc_hir_analysis/src/astconv/mod.rs @@ -2332,66 +2332,66 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { } fn check_delegation_constraints(&self, res_id: DefId, span: Span, emit: bool) -> bool { + #[inline] + fn generics_param_count(param_count: ty::GenericParamCount) -> usize { + param_count.lifetimes + param_count.types + param_count.consts + } + let mut error_occured = false; - let mut try_emit = |error| { + let res_span = self.tcx().def_span(res_id); + let mut try_emit = |descr| { if emit { - self.tcx().sess.emit_err(error); + self.tcx().sess.emit_err(crate::errors::NotSupportedDelegation { + span, + descr, + res_span, + }); } error_occured = true; }; - let res_span = self.tcx().def_span(res_id); + + if let Some(node) = self.tcx().hir().get_if_local(res_id) + && let Some(decl) = node.fn_decl() + && let hir::FnRetTy::Return(ty) = decl.output + { + match ty.kind { + hir::TyKind::InferDelegation(_, _) => try_emit("recursive delegation"), + hir::TyKind::OpaqueDef(_, _, _) => { + try_emit("delegation to a function with opaque type") + } + _ => {} + } + } let res_generics = self.tcx().generics_of(res_id); let parent = self.tcx().parent(self.item_def_id()); let parent_generics = self.tcx().generics_of(parent); let self_ty_bias = (self.tcx().def_kind(parent) == DefKind::Trait) as usize; - if parent_generics.count() + res_generics.own_counts().count() > self_ty_bias { - try_emit(super::errors::NotSupportedDelegation { - span, - descr: "early bound generics", - res_span, - }); + if parent_generics.count() + generics_param_count(res_generics.own_counts()) > self_ty_bias + { + try_emit("delegation with early bound generics"); } + if self.tcx().asyncness(res_id) == ty::Asyncness::Yes { - try_emit(super::errors::NotSupportedDelegation { - span, - descr: "async functions", - res_span, - }); + try_emit("delegation to async functions"); } if self.tcx().constness(res_id) == hir::Constness::Const { - try_emit(super::errors::NotSupportedDelegation { - span, - descr: "const functions", - res_span, - }); + try_emit("delegation to const functions"); } let res_sig = self.tcx().fn_sig(res_id).instantiate_identity(); if res_sig.c_variadic() { - try_emit(super::errors::NotSupportedDelegation { - span, - descr: "variadic functions", - res_span, - }); + try_emit("delegation to variadic functions"); return error_occured; } if let hir::Unsafety::Unsafe = res_sig.unsafety() { - try_emit(super::errors::NotSupportedDelegation { - span, - descr: "unsafe functions", - res_span, - }); + try_emit("delegation to unsafe functions"); } if abi::Abi::Rust != res_sig.abi() { - try_emit(super::errors::NotSupportedDelegation { - span, - descr: "non Rust ABI functions", - res_span, - }); + try_emit("delegation to non Rust ABI functions"); } error_occured @@ -2400,10 +2400,11 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { fn ty_from_delegation( &self, res_id: DefId, - idx: hir::InferDelegationVar, + idx: hir::InferDelegationKind, span: Span, ) -> Ty<'tcx> { - if self.check_delegation_constraints(res_id, span, idx == hir::InferDelegationVar::Output) { + if self.check_delegation_constraints(res_id, span, idx == hir::InferDelegationKind::Output) + { let e = self.tcx().sess.span_delayed_bug(span, "not supported delegation case"); self.set_tainted_by_errors(e); return Ty::new_error(self.tcx(), e); @@ -2411,26 +2412,20 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { let res_sig = self.tcx().fn_sig(res_id); let parent = self.tcx().parent(self.item_def_id()); - let item_def_kind = self.tcx().def_kind(self.item_def_id()); let parent_def_kind = self.tcx().def_kind(parent); - let res_sig = match (item_def_kind, parent_def_kind) { - (DefKind::AssocFn, DefKind::Impl { of_trait: true }) => { - let self_ty = self.tcx().type_of(parent).instantiate_identity(); - let generic_self_ty = ty::GenericArg::from(self_ty); - let substs = self.tcx().mk_args_from_iter(std::iter::once(generic_self_ty)); - res_sig.instantiate(self.tcx(), substs).skip_binder() - } - (DefKind::Fn, _) | (DefKind::AssocFn, _) => { - res_sig.instantiate_identity().skip_binder() - } - _ => span_bug!(span, "ty_from_delegation: couldn't calculate resolution signature"), + let res_sig = if let DefKind::Impl { of_trait: true } = parent_def_kind { + let self_ty = self.tcx().type_of(parent).instantiate_identity(); + let generic_self_ty = ty::GenericArg::from(self_ty); + let substs = self.tcx().mk_args_from_iter(std::iter::once(generic_self_ty)); + res_sig.instantiate(self.tcx(), substs).skip_binder() + } else { + res_sig.instantiate_identity().skip_binder() }; - if let hir::InferDelegationVar::Input(id) = idx { - res_sig.inputs()[id] - } else { - res_sig.output() + match idx { + hir::InferDelegationKind::Input(id) => res_sig.inputs()[id], + hir::InferDelegationKind::Output => res_sig.output(), } } diff --git a/compiler/rustc_middle/src/ty/generics.rs b/compiler/rustc_middle/src/ty/generics.rs index 61110e85fce03..c3699b114c411 100644 --- a/compiler/rustc_middle/src/ty/generics.rs +++ b/compiler/rustc_middle/src/ty/generics.rs @@ -122,12 +122,6 @@ pub struct GenericParamCount { pub consts: usize, } -impl GenericParamCount { - pub fn count(&self) -> usize { - self.lifetimes + self.types + self.consts - } -} - /// Information about the formal type/lifetime parameters associated /// with an item or method. Analogous to `hir::Generics`. /// diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 41bf80c22ee95..1ef3ce301abc0 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -204,7 +204,7 @@ pub struct ResolverAstLowering { /// Information about functions signatures for delegation items expansion pub has_self: LocalDefIdSet, - pub fns_arguments_count: FxHashMap, + pub fn_parameter_counts: LocalDefIdMap, } #[derive(Clone, Copy, Debug)] diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index d6d246e318876..65a4ba234602b 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -255,7 +255,7 @@ impl<'a> Parser<'a> { { // IMPL ITEM self.parse_item_impl(attrs, def_())? - } else if self.check_keyword(kw::Reuse) { + } else if self.is_reuse_path_item() { self.parse_item_delegation()? } else if self.check_keyword(kw::Mod) || self.check_keyword(kw::Unsafe) && self.is_keyword_ahead(1, &[kw::Mod]) @@ -363,7 +363,7 @@ impl<'a> Parser<'a> { fn is_reuse_path_item(&mut self) -> bool { self.is_kw_followed_by_ident(kw::Reuse) // no: `reuse::b`, yes: `reuse U::` // no: `reuse::b`, yes: reuse :: - || (self.token.is_keyword(kw::Reuse) && self.look_ahead(1, |t| *t == token::Lt)) + || (self.token.is_keyword(kw::Reuse) && self.look_ahead(1, |t| matches!(t.kind, token::Lt | token::BinOp(token::Shl)))) } /// Are we sure this could not possibly be a macro invocation? @@ -669,7 +669,6 @@ impl<'a> Parser<'a> { fn parse_item_delegation(&mut self) -> PResult<'a, ItemInfo> { self.expect_keyword(kw::Reuse)?; - let span = self.prev_token.span; let (qself, path) = if self.eat_lt() { let (qself, path) = self.parse_qpath(PathStyle::Expr)?; @@ -678,25 +677,17 @@ impl<'a> Parser<'a> { (None, self.parse_path(PathStyle::Expr)?) }; - let expr = if self.eat(&token::OpenDelim(Delimiter::Brace)) { - let expr = self.parse_expr()?; - self.expect(&token::CloseDelim(Delimiter::Brace))?; - Some(expr) + let body = if self.check(&token::OpenDelim(Delimiter::Brace)) { + Some(self.parse_block()?) } else { self.expect(&token::Semi)?; None }; - let ident = - path.segments.last().and_then(|segment| Some(segment.ident)).unwrap_or(Ident::empty()); + let ident = path.segments.last().map(|seg| seg.ident).unwrap_or(Ident::empty()); Ok(( ident, - ItemKind::Delegation(Box::new(Delegation { - id: DUMMY_NODE_ID, - path: (qself, path), - target_expr: expr, - span: span.to(self.prev_token.span), - })), + ItemKind::Delegation(Box::new(Delegation { id: DUMMY_NODE_ID, qself, path, body })), )) } diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index 453cada1bab73..0c46631b035df 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -16,7 +16,7 @@ use crate::{Resolver, ResolverArenas, Segment, ToNameBinding, VisResolutionError use rustc_ast::visit::{self, AssocCtxt, Visitor}; use rustc_ast::{self as ast, AssocItem, AssocItemKind, MetaItemKind, StmtKind}; -use rustc_ast::{Block, Fn, ForeignItem, ForeignItemKind, Impl, Item, ItemKind, NodeId}; +use rustc_ast::{Block, ForeignItem, ForeignItemKind, Impl, Item, ItemKind, NodeId}; use rustc_attr as attr; use rustc_data_structures::sync::Lrc; use rustc_errors::{struct_span_err, Applicability}; @@ -681,10 +681,7 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> { } // These items live in the value namespace. - ItemKind::Static(..) => { - self.r.define(parent, ident, ValueNS, (res, vis, sp, expansion)); - } - ItemKind::Const(..) => { + ItemKind::Const(..) | ItemKind::Delegation(..) | ItemKind::Static(..) => { self.r.define(parent, ident, ValueNS, (res, vis, sp, expansion)); } ItemKind::Fn(..) => { @@ -790,11 +787,6 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> { ItemKind::Impl(box Impl { of_trait: Some(..), .. }) => { self.r.trait_impl_items.insert(local_def_id); } - - ItemKind::Delegation(..) => { - let res = Res::Def(DefKind::Fn, def_id); - self.r.define(parent, ident, ValueNS, (res, vis, sp, expansion)); - } ItemKind::Impl { .. } | ItemKind::ForeignMod(..) | ItemKind::GlobalAsm(..) => {} ItemKind::MacroDef(..) | ItemKind::MacCall(_) => unreachable!(), @@ -1366,15 +1358,10 @@ impl<'a, 'b, 'tcx> Visitor<'b> for BuildReducedGraphVisitor<'a, 'b, 'tcx> { if ctxt == AssocCtxt::Trait { let ns = match item.kind { - AssocItemKind::Const(..) => ValueNS, - AssocItemKind::Fn(box Fn { ref sig, .. }) => { - if sig.decl.has_self() { - self.r.has_self.insert(local_def_id); - } - ValueNS - } + AssocItemKind::Const(..) + | AssocItemKind::Delegation(..) + | AssocItemKind::Fn(..) => ValueNS, AssocItemKind::Type(..) => TypeNS, - AssocItemKind::Delegation(..) => ValueNS, AssocItemKind::MacCall(_) => bug!(), // handled above }; diff --git a/compiler/rustc_resolve/src/def_collector.rs b/compiler/rustc_resolve/src/def_collector.rs index b7f90c93a5758..b77102c085c59 100644 --- a/compiler/rustc_resolve/src/def_collector.rs +++ b/compiler/rustc_resolve/src/def_collector.rs @@ -111,8 +111,7 @@ impl<'a, 'b, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'b, 'tcx> { ItemKind::TyAlias(..) => DefKind::TyAlias, ItemKind::Static(s) => DefKind::Static(s.mutability), ItemKind::Const(..) => DefKind::Const, - ItemKind::Fn(..) => DefKind::Fn, - ItemKind::Delegation(..) => DefKind::Fn, + ItemKind::Fn(..) | ItemKind::Delegation(..) => DefKind::Fn, ItemKind::MacroDef(..) => { let macro_data = self.resolver.compile_macro(i, self.resolver.tcx.sess.edition()); let macro_kind = macro_data.ext.macro_kind(); @@ -155,12 +154,8 @@ impl<'a, 'b, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'b, 'tcx> { }); } - fn visit_fn(&mut self, fn_kind: FnKind<'a>, span: Span, fn_id: NodeId) { + fn visit_fn(&mut self, fn_kind: FnKind<'a>, span: Span, _: NodeId) { if let FnKind::Fn(_, _, sig, _, generics, body) = fn_kind { - self.resolver - .fns_arguments_count - .insert(self.resolver.node_id_to_def_id[&fn_id].to_def_id(), sig.decl.inputs.len()); - match sig.header.coroutine_kind { Some(coroutine_kind) => { self.visit_generics(generics); @@ -264,10 +259,9 @@ impl<'a, 'b, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'b, 'tcx> { fn visit_assoc_item(&mut self, i: &'a AssocItem, ctxt: visit::AssocCtxt) { let def_kind = match &i.kind { - AssocItemKind::Fn(..) => DefKind::AssocFn, + AssocItemKind::Fn(..) | AssocItemKind::Delegation(..) => DefKind::AssocFn, AssocItemKind::Const(..) => DefKind::AssocConst, AssocItemKind::Type(..) => DefKind::AssocTy, - AssocItemKind::Delegation(..) => DefKind::AssocFn, AssocItemKind::MacCall(..) => return self.visit_macro_invoc(i.id), }; diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index f803e17b0c7ba..8d1fcdb4dcf79 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -540,13 +540,12 @@ impl<'a> PathSource<'a> { (PathSource::Type, false) => error_code!(E0412), (PathSource::Struct, true) => error_code!(E0574), (PathSource::Struct, false) => error_code!(E0422), - (PathSource::Expr(..), true) => error_code!(E0423), - (PathSource::Expr(..), false) => error_code!(E0425), + (PathSource::Expr(..), true) | (PathSource::Delegation, true) => error_code!(E0423), + (PathSource::Expr(..), false) | (PathSource::Delegation, false) => error_code!(E0425), (PathSource::Pat | PathSource::TupleStruct(..), true) => error_code!(E0532), (PathSource::Pat | PathSource::TupleStruct(..), false) => error_code!(E0531), (PathSource::TraitItem(..), true) => error_code!(E0575), (PathSource::TraitItem(..), false) => error_code!(E0576), - (PathSource::Delegation, _) => error_code!(E0795), } } } @@ -681,8 +680,6 @@ struct LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { /// If it is `true`, then it will be updated when entering a nested function or trait body. in_func_body: bool, - in_delegation_item: bool, - /// Count the number of places a lifetime is used. lifetime_uses: FxHashMap, } @@ -906,7 +903,6 @@ impl<'a: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast, } fn visit_fn(&mut self, fn_kind: FnKind<'ast>, sp: Span, fn_id: NodeId) { let previous_value = self.diagnostic_metadata.current_function; - match fn_kind { // Bail if the function is foreign, and thus cannot validly have // a body, or if there's no body for some other reason. @@ -1300,7 +1296,6 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { diagnostic_metadata: Default::default(), // errors at module scope should always be reported in_func_body: false, - in_delegation_item: false, lifetime_uses: Default::default(), } } @@ -1343,10 +1338,6 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { opt_ns: Option, // `None` indicates a module path in import finalize: Option, ) -> PathResult<'a> { - if self.in_delegation_item && path.len() == 1 && path[0].ident.name == kw::SelfLower { - return PathResult::NonModule(def::PartialRes::new(def::Res::Err)); - } - self.r.resolve_path_with_ribs( path, opt_ns, @@ -2536,14 +2527,12 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { } ItemKind::Delegation(ref delegation) => { - self.resolve_delegation(delegation, true); + self.resolve_delegation(item.id, delegation, false); } ItemKind::ExternCrate(..) => {} - ItemKind::MacCall(_) => { - panic!("unexpanded item in resolve!") - } + ItemKind::MacCall(_) => panic!("unexpanded macro in resolve!"), } } @@ -2818,13 +2807,15 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { walk_assoc_item(self, generics, LifetimeBinderKind::Function, item); } AssocItemKind::Delegation(delegation) => { - self.resolve_delegation(delegation, true); + self.resolve_delegation(item.id, delegation, false); } AssocItemKind::Type(box TyAlias { generics, .. }) => self .with_lifetime_rib(LifetimeRibKind::AnonymousReportError, |this| { walk_assoc_item(this, generics, LifetimeBinderKind::Item, item) }), - AssocItemKind::MacCall(_) => panic!("unexpanded assoc item in resolve!"), + AssocItemKind::MacCall(_) => { + panic!("unexpanded macro in resolve!") + } }; } @@ -3066,7 +3057,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { } AssocItemKind::Delegation(box delegation) => { debug!("resolve_implementation AssocItemKind::Delegation"); - let emitted = self.check_trait_item( + self.check_trait_item( item.id, item.ident, &item.kind, @@ -3075,9 +3066,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { seen_trait_items, |i, s, c| MethodNotMemberOfTrait(i, s, c), ); - - // do not emit same errors twice during path resolution - self.resolve_delegation(delegation, !emitted); + self.resolve_delegation(item.id, delegation, trait_id.is_some()); } AssocItemKind::MacCall(_) => { panic!("unexpanded macro in resolve!") @@ -3094,13 +3083,12 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { span: Span, seen_trait_items: &mut FxHashMap, err: F, - ) -> bool - where + ) where F: FnOnce(Ident, String, Option) -> ResolutionError<'a>, { // If there is a TraitRef in scope for an impl, then the method must be in the trait. let Some((module, _)) = self.current_trait_ref else { - return false; + return; }; ident.span.normalize_to_macros_2_0_and_adjust(module.expansion); let key = BindingKey::new(ident, ns); @@ -3124,7 +3112,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { let path = &self.current_trait_ref.as_ref().unwrap().1.path; let path_names = path_names_to_string(path); self.report_error(span, err(ident, path_names, candidate)); - return true; + return; }; let res = binding.res(); @@ -3140,7 +3128,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { trait_item_span: binding.span, }, ); - return false; + return; } Entry::Vacant(entry) => { entry.insert(span); @@ -3155,7 +3143,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { self.r.record_partial_res(id, PartialRes::new(res)); let vis = self.r.tcx.visibility(id_in_trait).expect_local(); self.r.feed_visibility(self.r.local_def_id(id), vis); - return false; + return; } _ => {} } @@ -3180,7 +3168,6 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { trait_item_span: binding.span, }, ); - true } fn resolve_const_body(&mut self, expr: &'ast Expr, item: Option<(Ident, ConstantItemKind)>) { @@ -3191,21 +3178,34 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { }) } - fn resolve_delegation(&mut self, delegation: &'ast Delegation, with_path: bool) { - self.in_delegation_item = true; - - let (qself, path) = &delegation.path; - if let Some(qself) = &delegation.path.0 { + fn resolve_delegation( + &mut self, + item_id: NodeId, + delegation: &'ast Delegation, + is_trait_impl: bool, + ) { + let (qself, path) = (&delegation.qself, &delegation.path); + if let Some(qself) = &delegation.qself { self.visit_ty(&qself.ty); } - if with_path { - self.smart_resolve_path(delegation.id, qself, path, PathSource::Delegation); + self.visit_path(path, delegation.id); + self.smart_resolve_path(delegation.id, qself, path, PathSource::Delegation); + if !is_trait_impl { + let path_res = self.r.partial_res_map.get(&delegation.id).unwrap(); + self.r.partial_res_map.insert(item_id, *path_res); } - if let Some(target_expr) = &delegation.target_expr { - self.visit_expr(target_expr); + if let Some(body) = &delegation.body { + // `PatBoundCtx` is not necessary in this context + let mut bindings = smallvec![(PatBoundCtx::Product, Default::default())]; + self.fresh_binding( + Ident::with_dummy_span(kw::SelfLower), + delegation.id, + PatternSource::FnParam, + &mut bindings, + ); + self.visit_block(body); } - self.in_delegation_item = false; } fn resolve_params(&mut self, params: &'ast [Param]) { @@ -4600,13 +4600,24 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { } } -struct LifetimeCountVisitor<'a, 'b, 'tcx> { +/// Walks the whole crate in DFS order, visiting each item, counting the declared number of +/// lifetime generic parameters and function parameters. +struct ItemInfoCollector<'a, 'b, 'tcx> { r: &'b mut Resolver<'a, 'tcx>, } -/// Walks the whole crate in DFS order, visiting each item, counting the declared number of -/// lifetime generic parameters. -impl<'ast> Visitor<'ast> for LifetimeCountVisitor<'_, '_, '_> { +impl ItemInfoCollector<'_, '_, '_> { + fn collect_fn_info(&mut self, sig: &FnSig, id: NodeId) { + let local_def_id = self.r.node_id_to_def_id[&id]; + self.r.fn_parameter_counts.insert(local_def_id, sig.decl.inputs.len()); + + if sig.decl.has_self() { + self.r.has_self.insert(local_def_id); + } + } +} + +impl<'ast> Visitor<'ast> for ItemInfoCollector<'_, '_, '_> { fn visit_item(&mut self, item: &'ast Item) { match &item.kind { ItemKind::TyAlias(box TyAlias { ref generics, .. }) @@ -4618,6 +4629,10 @@ impl<'ast> Visitor<'ast> for LifetimeCountVisitor<'_, '_, '_> { | ItemKind::Impl(box Impl { ref generics, .. }) | ItemKind::Trait(box Trait { ref generics, .. }) | ItemKind::TraitAlias(ref generics, _) => { + if let ItemKind::Fn(box Fn { ref sig, .. }) = &item.kind { + self.collect_fn_info(sig, item.id); + } + let def_id = self.r.local_def_id(item.id); let count = generics .params @@ -4634,16 +4649,28 @@ impl<'ast> Visitor<'ast> for LifetimeCountVisitor<'_, '_, '_> { | ItemKind::ExternCrate(..) | ItemKind::MacroDef(..) | ItemKind::GlobalAsm(..) - | ItemKind::MacCall(..) - | ItemKind::Delegation(..) => {} + | ItemKind::MacCall(..) => {} + ItemKind::Delegation(..) => { + // Delegated functions have lifetimes, their count is not necessarily zero. + // But skipping the delegation items here doesn't mean that the count will be considered zero, + // it means there will be a panic when retrieving the count, + // but for delegation items we are never actually retrieving that count in practice. + } } visit::walk_item(self, item) } + + fn visit_assoc_item(&mut self, item: &'ast AssocItem, ctxt: AssocCtxt) { + if let AssocItemKind::Fn(box Fn { ref sig, .. }) = &item.kind { + self.collect_fn_info(sig, item.id); + } + visit::walk_assoc_item(self, item, ctxt); + } } impl<'a, 'tcx> Resolver<'a, 'tcx> { pub(crate) fn late_resolve_crate(&mut self, krate: &Crate) { - visit::walk_crate(&mut LifetimeCountVisitor { r: self }, krate); + visit::walk_crate(&mut ItemInfoCollector { r: self }, krate); let mut late_resolution_visitor = LateResolutionVisitor::new(self); late_resolution_visitor.resolve_doc_links(&krate.attrs, MaybeExported::Ok(CRATE_NODE_ID)); visit::walk_crate(&mut late_resolution_visitor, krate); diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index 13cd260cd0382..95c8bf572c5e7 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -221,18 +221,6 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { let mut span_label = None; let item_ident = path.last().unwrap().ident; let item_span = item_ident.span; - if let PathSource::Delegation = source { - return BaseError { - msg: format!("couldn't resolve `{item_str}` in delegation item"), - fallback_label: "delegation is only supported yet for trait methods with explicit paths and free functions".to_string(), - span: item_span, - span_label, - could_be_expr: false, - suggestion: None, - module: None, - }; - } - let (mod_prefix, mod_str, module, suggestion) = if path.len() == 1 { debug!(?self.diagnostic_metadata.current_impl_items); debug!(?self.diagnostic_metadata.current_function); @@ -447,13 +435,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { code, ); - // FIXME: suggestions do not supported yet for delegation item - if let PathSource::Delegation = source { - err.span_label(base_error.span, base_error.fallback_label); - return (err, Vec::new()); - } self.suggest_at_operator_in_slice_pat_with_range(&mut err, path); - self.suggest_swapping_misplaced_self_ty_and_trait(&mut err, source, res, base_error.span); if let Some((span, label)) = base_error.span_label { @@ -608,6 +590,10 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { res: Option, base_error: &BaseError, ) -> (bool, Vec) { + if let PathSource::Delegation = source { + return (false, vec![]); + } + // Try to lookup name in more relaxed fashion for better error reporting. let ident = path.last().unwrap().ident; let is_expected = &|res| source.is_expected(res); diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index d367e45a18d6c..b3cb80b346b1f 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -1101,6 +1101,8 @@ pub struct Resolver<'a, 'tcx> { legacy_const_generic_args: FxHashMap>>, /// Amount of lifetime parameters for each item in the crate. item_generics_num_lifetimes: FxHashMap, + /// Amount of parameters for each function in the crate. + fn_parameter_counts: LocalDefIdMap, main_def: Option, trait_impls: FxIndexMap>, @@ -1118,8 +1120,6 @@ pub struct Resolver<'a, 'tcx> { doc_link_resolutions: FxHashMap, doc_link_traits_in_scope: FxHashMap>, all_macro_rules: FxHashMap, - - fns_arguments_count: FxHashMap, } /// Nothing really interesting here; it just provides memory for the rest of the crate. @@ -1444,7 +1444,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { doc_link_resolutions: Default::default(), doc_link_traits_in_scope: Default::default(), all_macro_rules: Default::default(), - fns_arguments_count: Default::default(), + fn_parameter_counts: Default::default(), }; let root_parent_scope = ParentScope::module(graph_root, &resolver); @@ -1549,7 +1549,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { lifetime_elision_allowed: self.lifetime_elision_allowed, lint_buffer: Steal::new(self.lint_buffer), has_self: self.has_self, - fns_arguments_count: self.fns_arguments_count, + fn_parameter_counts: self.fn_parameter_counts, }; ResolverOutputs { global_ctxt, ast_lowering } } diff --git a/tests/ui/delegation/bad-resolve.rs b/tests/ui/delegation/bad-resolve.rs index a1bc9534b27f9..d7c5ef52813aa 100644 --- a/tests/ui/delegation/bad-resolve.rs +++ b/tests/ui/delegation/bad-resolve.rs @@ -17,28 +17,28 @@ impl F { struct S(F); impl Trait for S { -//~^ not all trait items implemented, missing: `Type` +//~^ ERROR not all trait items implemented, missing: `Type` reuse ::C; //~^ ERROR item `C` is an associated method, which doesn't match its trait `Trait` + //~| ERROR expected function, found associated constant `Trait::C` reuse ::Type; //~^ ERROR item `Type` is an associated method, which doesn't match its trait `Trait` + //~| ERROR expected method or associated constant, found associated type `Trait::Type` reuse ::baz; //~^ ERROR method `baz` is not a member of trait `Trait` + //~| ERROR cannot find method or associated constant `baz` in trait `Trait` reuse ::bar; reuse foo { &self.0 } - //~^ ERROR couldn't resolve `foo` in delegation item - //~| method `foo` has a `&self` declaration in the trait, but not in the impl + //~^ ERROR cannot find function `foo` in this scope reuse F::foo { &self.0 } - //~^ ERROR couldn't resolve `foo` in delegation item + //~^ ERROR cannot find function `foo` in `F` //~| ERROR duplicate definitions with name `foo` } impl S { reuse F::foo { &self.0 } - //~^ ERROR couldn't resolve `foo` in delegation item + //~^ ERROR cannot find function `foo` in `F` } -fn main() { - -} +fn main() {} diff --git a/tests/ui/delegation/bad-resolve.stderr b/tests/ui/delegation/bad-resolve.stderr index f6dd9f2282fe9..60ade9aa80657 100644 --- a/tests/ui/delegation/bad-resolve.stderr +++ b/tests/ui/delegation/bad-resolve.stderr @@ -8,7 +8,7 @@ LL | reuse ::C; | ^^^^^^^^^^^^^^^^^^^^^^ does not match trait error[E0324]: item `Type` is an associated method, which doesn't match its trait `Trait` - --> $DIR/bad-resolve.rs:23:5 + --> $DIR/bad-resolve.rs:24:5 | LL | type Type; | ---------- item in trait @@ -17,7 +17,7 @@ LL | reuse ::Type; | ^^^^^^^^^^^^^^^^^^^^^^^^^ does not match trait error[E0407]: method `baz` is not a member of trait `Trait` - --> $DIR/bad-resolve.rs:25:5 + --> $DIR/bad-resolve.rs:27:5 | LL | reuse ::baz; | ^^^^^^^^^^^^^^^^^^^^---^ @@ -26,43 +26,57 @@ LL | reuse ::baz; | not a member of trait `Trait` error[E0201]: duplicate definitions with name `foo`: - --> $DIR/bad-resolve.rs:32:5 + --> $DIR/bad-resolve.rs:34:5 | LL | fn foo(&self, x: i32) -> i32 { x } | ---------------------------------- item in trait ... LL | reuse foo { &self.0 } | --------------------- previous definition here -... +LL | LL | reuse F::foo { &self.0 } | ^^^^^^^^^^^^^^^^^^^^^^^^ duplicate definition -error[E0795]: couldn't resolve `foo` in delegation item - --> $DIR/bad-resolve.rs:29:11 +error[E0423]: expected function, found associated constant `Trait::C` + --> $DIR/bad-resolve.rs:21:11 | -LL | reuse foo { &self.0 } - | ^^^ delegation is only supported yet for trait methods with explicit paths and free functions +LL | reuse ::C; + | ^^^^^^^^^^^^^^^ not a function -error[E0795]: couldn't resolve `foo` in delegation item - --> $DIR/bad-resolve.rs:32:14 +error[E0575]: expected method or associated constant, found associated type `Trait::Type` + --> $DIR/bad-resolve.rs:24:11 | -LL | reuse F::foo { &self.0 } - | ^^^ delegation is only supported yet for trait methods with explicit paths and free functions - -error[E0795]: couldn't resolve `foo` in delegation item - --> $DIR/bad-resolve.rs:38:14 +LL | reuse ::Type; + | ^^^^^^^^^^^^^^^^^^ | -LL | reuse F::foo { &self.0 } - | ^^^ delegation is only supported yet for trait methods with explicit paths and free functions + = note: can't use a type alias as a constructor -error[E0186]: method `foo` has a `&self` declaration in the trait, but not in the impl - --> $DIR/bad-resolve.rs:29:5 +error[E0576]: cannot find method or associated constant `baz` in trait `Trait` + --> $DIR/bad-resolve.rs:27:25 | -LL | fn foo(&self, x: i32) -> i32 { x } - | ---------------------------- `&self` used in trait +LL | fn bar() {} + | -------- similarly named associated function `bar` defined here ... +LL | reuse ::baz; + | ^^^ help: an associated function with a similar name exists: `bar` + +error[E0425]: cannot find function `foo` in this scope + --> $DIR/bad-resolve.rs:32:11 + | LL | reuse foo { &self.0 } - | ^^^^^^^^^^^^^^^^^^^^^ expected `&self` in impl + | ^^^ not found in this scope + +error[E0425]: cannot find function `foo` in `F` + --> $DIR/bad-resolve.rs:34:14 + | +LL | reuse F::foo { &self.0 } + | ^^^ not found in `F` + +error[E0425]: cannot find function `foo` in `F` + --> $DIR/bad-resolve.rs:40:14 + | +LL | reuse F::foo { &self.0 } + | ^^^ not found in `F` error[E0046]: not all trait items implemented, missing: `Type` --> $DIR/bad-resolve.rs:19:1 @@ -73,7 +87,7 @@ LL | type Type; LL | impl Trait for S { | ^^^^^^^^^^^^^^^^ missing `Type` in implementation -error: aborting due to 9 previous errors +error: aborting due to 11 previous errors -Some errors have detailed explanations: E0046, E0186, E0201, E0324, E0407, E0795. +Some errors have detailed explanations: E0046, E0201, E0324, E0407, E0423, E0425, E0575, E0576. For more information about an error, try `rustc --explain E0046`. diff --git a/tests/ui/delegation/explicit-paths-pass.rs b/tests/ui/delegation/explicit-paths-pass.rs index 85f24c5106433..73c8841619ef7 100644 --- a/tests/ui/delegation/explicit-paths-pass.rs +++ b/tests/ui/delegation/explicit-paths-pass.rs @@ -16,12 +16,12 @@ trait Trait { struct F; impl Trait for F {} -mod reuse { +mod to_reuse { pub fn foo(x: i32) -> i32 { x + 1 } pub fn zero_args() -> i32 { 15 } } -reuse reuse::zero_args { self } +reuse to_reuse::zero_args { self } struct S(F); impl Trait for S { @@ -33,7 +33,7 @@ impl Trait for S { } impl S { - reuse ::static_method { reuse::foo(self) } + reuse ::static_method { to_reuse::foo(self) } } impl std::fmt::Display for S { @@ -54,7 +54,7 @@ fn main() { reuse ::static_method; reuse ::static_method2 { static_method(self) } #[inline] - reuse reuse::foo; + reuse to_reuse::foo; assert_eq!(42, static_method(42)); assert_eq!(21, static_method2(10, 10)); assert_eq!(43, foo(42)); diff --git a/tests/ui/delegation/explicit-paths-signature-pass.rs b/tests/ui/delegation/explicit-paths-signature-pass.rs new file mode 100644 index 0000000000000..4910f458f680f --- /dev/null +++ b/tests/ui/delegation/explicit-paths-signature-pass.rs @@ -0,0 +1,30 @@ +// run-pass + +mod to_reuse { + use crate::S; + + pub fn foo<'a>(#[cfg(FALSE)] a: u8, _b: &'a S) -> u32 { + 1 + } +} + +reuse to_reuse::foo; + +trait Trait { + fn foo(&self) -> u32 { 0 } +} + +struct F; +impl Trait for F {} + +struct S(F); + +impl Trait for S { + reuse to_reuse::foo { self } +} + +fn main() { + let s = S(F); + assert_eq!(1, foo(&s)); + assert_eq!(1, s.foo()); +} diff --git a/tests/ui/delegation/explicit-paths.stderr b/tests/ui/delegation/explicit-paths.stderr index 4032f5954cd60..8288a9851f254 100644 --- a/tests/ui/delegation/explicit-paths.stderr +++ b/tests/ui/delegation/explicit-paths.stderr @@ -19,17 +19,10 @@ error[E0308]: mismatched types --> $DIR/explicit-paths.rs:18:32 | LL | reuse ::bar { &self.0 } - | ------------------ ^^^^^^^ expected `&S2`, found `&F` - | | - | arguments to this function are incorrect + | ^^^^^^^ expected `&S2`, found `&F` | = note: expected reference `&S2` found reference `&F` -note: method defined here - --> $DIR/explicit-paths.rs:2:8 - | -LL | fn bar(&self) -> i32 { 42 } - | ^^^ ----- error: aborting due to 2 previous errors diff --git a/tests/ui/delegation/not-supported.rs b/tests/ui/delegation/not-supported.rs index 577d0c784cc13..d77996c7fef90 100644 --- a/tests/ui/delegation/not-supported.rs +++ b/tests/ui/delegation/not-supported.rs @@ -41,12 +41,21 @@ mod generics { reuse ::foo { &self.0 } //~^ ERROR delegation with early bound generics is not supported yet } +} + +mod opaque { + trait Trait {} mod to_reuse { - pub fn opaque(_: impl super::Trait) -> i32 { 0 } + use super::Trait; + + pub fn opaque_arg(_: impl Trait) -> i32 { 0 } + pub fn opaque_ret() -> impl Trait { unimplemented!() } } - reuse to_reuse::opaque; + reuse to_reuse::opaque_arg; //~^ ERROR delegation with early bound generics is not supported yet + reuse to_reuse::opaque_ret; + //~^ ERROR delegation to a function with opaque type is not supported yet } mod fn_header { @@ -58,13 +67,26 @@ mod fn_header { } reuse to_reuse::unsafe_fn; - //~^ ERROR delegation with unsafe functions is not supported yet + //~^ ERROR delegation to unsafe functions is not supported yet reuse to_reuse::extern_fn; - //~^ ERROR delegation with non Rust ABI functions is not supported yet + //~^ ERROR delegation to non Rust ABI functions is not supported yet reuse to_reuse::variadic_fn; - //~^ ERROR delegation with variadic functions is not supported yet + //~^ ERROR delegation to variadic functions is not supported yet reuse to_reuse::const_fn; - //~^ ERROR delegation with const functions is not supported yet + //~^ ERROR delegation to const functions is not supported yet +} + +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 } fn main() {} diff --git a/tests/ui/delegation/not-supported.stderr b/tests/ui/delegation/not-supported.stderr index 59eee4381ff6e..3c5bf533b389f 100644 --- a/tests/ui/delegation/not-supported.stderr +++ b/tests/ui/delegation/not-supported.stderr @@ -1,12 +1,3 @@ -error: delegation with early bound generics is not supported yet - --> $DIR/not-supported.rs:48:5 - | -LL | pub fn opaque(_: impl super::Trait) -> i32 { 0 } - | ------------------------------------------ callee defined here -LL | } -LL | reuse to_reuse::opaque; - | ^^^^^^^^^^^^^^^^^^^^^^^ - error: delegation with early bound generics is not supported yet --> $DIR/not-supported.rs:22:9 | @@ -52,8 +43,26 @@ LL | fn foo(&self, x: i32) -> i32 { x } LL | reuse ::foo { &self.0 } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: delegation with unsafe functions is not supported yet - --> $DIR/not-supported.rs:60:5 +error: delegation with early bound generics is not supported yet + --> $DIR/not-supported.rs:55:5 + | +LL | pub fn opaque_arg(_: impl Trait) -> i32 { 0 } + | --------------------------------------- callee defined here +... +LL | reuse to_reuse::opaque_arg; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: delegation to a function with opaque type is not supported yet + --> $DIR/not-supported.rs:57:5 + | +LL | pub fn opaque_ret() -> impl Trait { unimplemented!() } + | --------------------------------- callee defined here +... +LL | reuse to_reuse::opaque_ret; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: delegation to unsafe functions is not supported yet + --> $DIR/not-supported.rs:69:5 | LL | pub unsafe fn unsafe_fn() {} | ------------------------- callee defined here @@ -61,8 +70,8 @@ LL | pub unsafe fn unsafe_fn() {} LL | reuse to_reuse::unsafe_fn; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: delegation with non Rust ABI functions is not supported yet - --> $DIR/not-supported.rs:62:5 +error: delegation to non Rust ABI functions is not supported yet + --> $DIR/not-supported.rs:71:5 | LL | pub extern "C" fn extern_fn() {} | ----------------------------- callee defined here @@ -70,8 +79,8 @@ LL | pub extern "C" fn extern_fn() {} LL | reuse to_reuse::extern_fn; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: delegation with variadic functions is not supported yet - --> $DIR/not-supported.rs:64:5 +error: delegation to variadic functions is not supported yet + --> $DIR/not-supported.rs:73:5 | LL | pub unsafe extern "C" fn variadic_fn(n: usize, mut args: ...) {} | ------------------------------------------------------------- callee defined here @@ -79,8 +88,8 @@ LL | pub unsafe extern "C" fn variadic_fn(n: usize, mut args: ...) {} LL | reuse to_reuse::variadic_fn; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: delegation with const functions is not supported yet - --> $DIR/not-supported.rs:66:5 +error: delegation to const functions is not supported yet + --> $DIR/not-supported.rs:75:5 | LL | pub const fn const_fn() {} | ----------------------- callee defined here @@ -88,5 +97,14 @@ LL | pub const fn const_fn() {} LL | reuse to_reuse::const_fn; | ^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 10 previous errors +error: recursive delegation is not supported yet + --> $DIR/not-supported.rs:88:5 + | +LL | pub reuse to_reuse2::foo; + | ------------------------- callee defined here +... +LL | reuse to_reuse1::foo; + | ^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 12 previous errors diff --git a/tests/ui/delegation/parse.rs b/tests/ui/delegation/parse.rs index 5732d21804f5d..e92c85304c2d9 100644 --- a/tests/ui/delegation/parse.rs +++ b/tests/ui/delegation/parse.rs @@ -1,4 +1,8 @@ +macro_rules! reuse { {} => {} } + mod reuse { + use crate::reuse; + pub fn to_unsafe(x: i32) -> i32 { x + 1 } pub fn to_pub() {} @@ -9,13 +13,19 @@ mod reuse { c: i32, } + impl reuse { + reuse!(); + } + #[allow(unused)] fn baz() { let (a, b, c) = (0, 0, 0); - let _ = reuse {a, b, c}; + reuse {a, b, c}; } } +reuse!(); + unsafe reuse reuse::to_unsafe; //~^ ERROR expected item, found keyword `unsafe` #[inline] diff --git a/tests/ui/delegation/parse.stderr b/tests/ui/delegation/parse.stderr index d4b289accb8ae..e6d2c7ce2f09e 100644 --- a/tests/ui/delegation/parse.stderr +++ b/tests/ui/delegation/parse.stderr @@ -1,5 +1,5 @@ error: expected item, found keyword `unsafe` - --> $DIR/parse.rs:19:1 + --> $DIR/parse.rs:29:1 | LL | unsafe reuse reuse::to_unsafe; | ^^^^^^ expected item