mirror of
https://github.com/rust-lang/rust.git
synced 2025-02-20 10:55:14 +00:00
Delegation implementation: step 1
This commit is contained in:
parent
2b1365b34f
commit
d69cd6473c
@ -2873,6 +2873,7 @@ impl Item {
|
||||
| ItemKind::ForeignMod(_)
|
||||
| ItemKind::GlobalAsm(_)
|
||||
| ItemKind::MacCall(_)
|
||||
| ItemKind::Delegation(_)
|
||||
| ItemKind::MacroDef(_) => None,
|
||||
ItemKind::Static(_) => None,
|
||||
ItemKind::Const(i) => Some(&i.generics),
|
||||
@ -3019,6 +3020,15 @@ pub struct Fn {
|
||||
pub body: Option<P<Block>>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Encodable, Decodable, Debug)]
|
||||
pub struct Delegation {
|
||||
/// Path resolution id.
|
||||
pub id: NodeId,
|
||||
pub qself: Option<P<QSelf>>,
|
||||
pub path: Path,
|
||||
pub body: Option<P<Block>>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Encodable, Decodable, Debug)]
|
||||
pub struct StaticItem {
|
||||
pub ty: P<Ty>,
|
||||
@ -3104,6 +3114,11 @@ pub enum ItemKind {
|
||||
|
||||
/// A macro definition.
|
||||
MacroDef(MacroDef),
|
||||
|
||||
/// A delegation item (`reuse`).
|
||||
///
|
||||
/// E.g. `reuse <Type as Trait>::name { target_expr_template }`.
|
||||
Delegation(Box<Delegation>),
|
||||
}
|
||||
|
||||
impl ItemKind {
|
||||
@ -3111,7 +3126,8 @@ impl ItemKind {
|
||||
use ItemKind::*;
|
||||
match self {
|
||||
Use(..) | Static(..) | Const(..) | Fn(..) | Mod(..) | GlobalAsm(..) | TyAlias(..)
|
||||
| Struct(..) | Union(..) | Trait(..) | TraitAlias(..) | MacroDef(..) => "a",
|
||||
| Struct(..) | Union(..) | Trait(..) | TraitAlias(..) | MacroDef(..)
|
||||
| Delegation(..) => "a",
|
||||
ExternCrate(..) | ForeignMod(..) | MacCall(..) | Enum(..) | Impl { .. } => "an",
|
||||
}
|
||||
}
|
||||
@ -3135,6 +3151,7 @@ impl ItemKind {
|
||||
ItemKind::MacCall(..) => "item macro invocation",
|
||||
ItemKind::MacroDef(..) => "macro definition",
|
||||
ItemKind::Impl { .. } => "implementation",
|
||||
ItemKind::Delegation(..) => "delegated function",
|
||||
}
|
||||
}
|
||||
|
||||
@ -3176,6 +3193,8 @@ pub enum AssocItemKind {
|
||||
Type(Box<TyAlias>),
|
||||
/// A macro expanding to associated items.
|
||||
MacCall(P<MacCall>),
|
||||
/// An associated delegation item.
|
||||
Delegation(Box<Delegation>),
|
||||
}
|
||||
|
||||
impl AssocItemKind {
|
||||
@ -3184,7 +3203,7 @@ impl AssocItemKind {
|
||||
Self::Const(box ConstItem { defaultness, .. })
|
||||
| Self::Fn(box Fn { defaultness, .. })
|
||||
| Self::Type(box TyAlias { defaultness, .. }) => defaultness,
|
||||
Self::MacCall(..) => Defaultness::Final,
|
||||
Self::MacCall(..) | Self::Delegation(..) => Defaultness::Final,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -3196,6 +3215,7 @@ impl From<AssocItemKind> for ItemKind {
|
||||
AssocItemKind::Fn(fn_kind) => ItemKind::Fn(fn_kind),
|
||||
AssocItemKind::Type(ty_alias_kind) => ItemKind::TyAlias(ty_alias_kind),
|
||||
AssocItemKind::MacCall(a) => ItemKind::MacCall(a),
|
||||
AssocItemKind::Delegation(delegation) => ItemKind::Delegation(delegation),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -3209,6 +3229,7 @@ impl TryFrom<ItemKind> for AssocItemKind {
|
||||
ItemKind::Fn(fn_kind) => AssocItemKind::Fn(fn_kind),
|
||||
ItemKind::TyAlias(ty_kind) => AssocItemKind::Type(ty_kind),
|
||||
ItemKind::MacCall(a) => AssocItemKind::MacCall(a),
|
||||
ItemKind::Delegation(d) => AssocItemKind::Delegation(d),
|
||||
_ => return Err(item_kind),
|
||||
})
|
||||
}
|
||||
|
@ -1117,6 +1117,14 @@ pub fn noop_visit_item_kind<T: MutVisitor>(kind: &mut ItemKind, vis: &mut T) {
|
||||
}
|
||||
ItemKind::MacCall(m) => vis.visit_mac_call(m),
|
||||
ItemKind::MacroDef(def) => vis.visit_macro_def(def),
|
||||
ItemKind::Delegation(box Delegation { id, qself, path, body }) => {
|
||||
vis.visit_id(id);
|
||||
vis.visit_qself(qself);
|
||||
vis.visit_path(path);
|
||||
if let Some(body) = body {
|
||||
vis.visit_block(body);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1155,6 +1163,14 @@ pub fn noop_flat_map_assoc_item<T: MutVisitor>(
|
||||
visit_opt(ty, |ty| visitor.visit_ty(ty));
|
||||
}
|
||||
AssocItemKind::MacCall(mac) => visitor.visit_mac_call(mac),
|
||||
AssocItemKind::Delegation(box Delegation { id, qself, path, body }) => {
|
||||
visitor.visit_id(id);
|
||||
visitor.visit_qself(qself);
|
||||
visitor.visit_path(path);
|
||||
if let Some(body) = body {
|
||||
visitor.visit_block(body);
|
||||
}
|
||||
}
|
||||
}
|
||||
visitor.visit_span(span);
|
||||
visit_lazy_tts(tokens, visitor);
|
||||
|
@ -375,6 +375,15 @@ 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 { id: _, qself, path, body }) => {
|
||||
if let Some(qself) = qself {
|
||||
visitor.visit_ty(&qself.ty);
|
||||
}
|
||||
walk_path(visitor, path);
|
||||
if let Some(body) = body {
|
||||
visitor.visit_block(body);
|
||||
}
|
||||
}
|
||||
}
|
||||
walk_list!(visitor, visit_attribute, &item.attrs);
|
||||
}
|
||||
@ -704,6 +713,15 @@ pub fn walk_assoc_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a AssocItem,
|
||||
AssocItemKind::MacCall(mac) => {
|
||||
visitor.visit_mac_call(mac);
|
||||
}
|
||||
AssocItemKind::Delegation(box Delegation { id: _, qself, path, body }) => {
|
||||
if let Some(qself) = qself {
|
||||
visitor.visit_ty(&qself.ty);
|
||||
}
|
||||
walk_path(visitor, path);
|
||||
if let Some(body) = body {
|
||||
visitor.visit_block(body);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
348
compiler/rustc_ast_lowering/src/delegation.rs
Normal file
348
compiler/rustc_ast_lowering/src/delegation.rs
Normal file
@ -0,0 +1,348 @@
|
||||
//! This module implements expansion of delegation items with early resolved paths.
|
||||
//! It includes a delegation to a free functions:
|
||||
//!
|
||||
//! ```ignore (illustrative)
|
||||
//! reuse module::name { target_expr_template }
|
||||
//! ```
|
||||
//!
|
||||
//! And delegation to a trait methods:
|
||||
//!
|
||||
//! ```ignore (illustrative)
|
||||
//! reuse <Type as Trait>::name { target_expr_template }
|
||||
//! ```
|
||||
//!
|
||||
//! After expansion for both cases we get:
|
||||
//!
|
||||
//! ```ignore (illustrative)
|
||||
//! fn name(
|
||||
//! arg0: InferDelegation(sig_id, Input(0)),
|
||||
//! arg1: InferDelegation(sig_id, Input(1)),
|
||||
//! ...,
|
||||
//! argN: InferDelegation(sig_id, Input(N)),
|
||||
//! ) -> InferDelegation(sig_id, Output) {
|
||||
//! callee_path(target_expr_template(arg0), arg1, ..., argN)
|
||||
//! }
|
||||
//! ```
|
||||
//!
|
||||
//! Where `callee_path` is a path in delegation item e.g. `<Type as Trait>::name`.
|
||||
//! `sig_id` is a id of item from which the signature is inherited. It may be a delegation
|
||||
//! item id (`item_id`) in case of impl trait or path resolution id (`path_id`) otherwise.
|
||||
//!
|
||||
//! Since we do not have a proper way to obtain function type information by path resolution
|
||||
//! in AST, we mark each function parameter type as `InferDelegation` and inherit it in `AstConv`.
|
||||
//!
|
||||
//! Similarly generics, predicates and header are set to the "default" values.
|
||||
//! In case of discrepancy with callee function the `NotSupportedDelegation` error will
|
||||
//! also be emitted in `AstConv`.
|
||||
|
||||
use crate::{ImplTraitPosition, ResolverAstLoweringExt};
|
||||
|
||||
use super::{ImplTraitContext, LoweringContext, ParamMode};
|
||||
|
||||
use ast::visit::Visitor;
|
||||
use hir::def::{DefKind, PartialRes, Res};
|
||||
use hir::{BodyId, HirId};
|
||||
use rustc_ast as ast;
|
||||
use rustc_ast::*;
|
||||
use rustc_errors::ErrorGuaranteed;
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_middle::span_bug;
|
||||
use rustc_middle::ty::ResolverAstLowering;
|
||||
use rustc_span::{symbol::Ident, Span};
|
||||
use rustc_target::spec::abi;
|
||||
use std::iter;
|
||||
|
||||
pub(crate) struct DelegationResults<'hir> {
|
||||
pub body_id: hir::BodyId,
|
||||
pub sig: hir::FnSig<'hir>,
|
||||
pub generics: &'hir hir::Generics<'hir>,
|
||||
}
|
||||
|
||||
impl<'hir> LoweringContext<'_, 'hir> {
|
||||
pub(crate) fn delegation_has_self(&self, item_id: NodeId, path_id: NodeId, span: Span) -> bool {
|
||||
let sig_id = self.get_delegation_sig_id(item_id, path_id, span);
|
||||
let Ok(sig_id) = sig_id else {
|
||||
return false;
|
||||
};
|
||||
if let Some(local_sig_id) = sig_id.as_local() {
|
||||
self.resolver.has_self.contains(&local_sig_id)
|
||||
} else {
|
||||
match self.tcx.def_kind(sig_id) {
|
||||
DefKind::Fn => false,
|
||||
DefKind::AssocFn => self.tcx.associated_item(sig_id).fn_has_self_parameter,
|
||||
_ => span_bug!(span, "unexpected DefKind for delegation item"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn lower_delegation(
|
||||
&mut self,
|
||||
delegation: &Delegation,
|
||||
item_id: NodeId,
|
||||
) -> DelegationResults<'hir> {
|
||||
let span = delegation.path.segments.last().unwrap().ident.span;
|
||||
let sig_id = self.get_delegation_sig_id(item_id, delegation.id, span);
|
||||
match sig_id {
|
||||
Ok(sig_id) => {
|
||||
let decl = self.lower_delegation_decl(sig_id, span);
|
||||
let sig = self.lower_delegation_sig(span, decl);
|
||||
let body_id = self.lower_delegation_body(sig.decl, delegation);
|
||||
|
||||
let generics = self.lower_delegation_generics(span);
|
||||
DelegationResults { body_id, sig, generics }
|
||||
}
|
||||
Err(err) => self.generate_delegation_error(err, span),
|
||||
}
|
||||
}
|
||||
|
||||
fn get_delegation_sig_id(
|
||||
&self,
|
||||
item_id: NodeId,
|
||||
path_id: NodeId,
|
||||
span: Span,
|
||||
) -> Result<DefId, ErrorGuaranteed> {
|
||||
let sig_id = if self.is_in_trait_impl { item_id } else { path_id };
|
||||
let sig_id = self
|
||||
.resolver
|
||||
.get_partial_res(sig_id)
|
||||
.map(|r| r.expect_full_res().opt_def_id())
|
||||
.unwrap_or(None);
|
||||
|
||||
sig_id.ok_or_else(|| {
|
||||
self.tcx
|
||||
.dcx()
|
||||
.span_delayed_bug(span, "LoweringContext: couldn't resolve delegation item")
|
||||
})
|
||||
}
|
||||
|
||||
fn lower_delegation_generics(&mut self, span: Span) -> &'hir hir::Generics<'hir> {
|
||||
self.arena.alloc(hir::Generics {
|
||||
params: &[],
|
||||
predicates: &[],
|
||||
has_where_clause_predicates: false,
|
||||
where_clause_span: span,
|
||||
span: span,
|
||||
})
|
||||
}
|
||||
|
||||
fn lower_delegation_decl(
|
||||
&mut self,
|
||||
sig_id: DefId,
|
||||
param_span: Span,
|
||||
) -> &'hir hir::FnDecl<'hir> {
|
||||
let args_count = if let Some(local_sig_id) = sig_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_sig_id).cloned().unwrap_or_default()
|
||||
} else {
|
||||
self.tcx.fn_arg_names(sig_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(sig_id, hir::InferDelegationKind::Input(arg)),
|
||||
span: self.lower_span(param_span),
|
||||
}));
|
||||
|
||||
let output = self.arena.alloc(hir::Ty {
|
||||
hir_id: self.next_id(),
|
||||
kind: hir::TyKind::InferDelegation(sig_id, hir::InferDelegationKind::Output),
|
||||
span: self.lower_span(param_span),
|
||||
});
|
||||
|
||||
self.arena.alloc(hir::FnDecl {
|
||||
inputs,
|
||||
output: hir::FnRetTy::Return(output),
|
||||
c_variadic: false,
|
||||
lifetime_elision_allowed: true,
|
||||
implicit_self: hir::ImplicitSelfKind::None,
|
||||
})
|
||||
}
|
||||
|
||||
fn lower_delegation_sig(
|
||||
&mut self,
|
||||
span: Span,
|
||||
decl: &'hir hir::FnDecl<'hir>,
|
||||
) -> hir::FnSig<'hir> {
|
||||
hir::FnSig {
|
||||
decl,
|
||||
header: hir::FnHeader {
|
||||
unsafety: hir::Unsafety::Normal,
|
||||
constness: hir::Constness::NotConst,
|
||||
asyncness: hir::IsAsync::NotAsync,
|
||||
abi: abi::Abi::Rust,
|
||||
},
|
||||
span: self.lower_span(span),
|
||||
}
|
||||
}
|
||||
|
||||
fn generate_param(&mut self, ty: &'hir hir::Ty<'hir>) -> (hir::Param<'hir>, NodeId) {
|
||||
let pat_node_id = self.next_node_id();
|
||||
let pat_id = self.lower_node_id(pat_node_id);
|
||||
let pat = self.arena.alloc(hir::Pat {
|
||||
hir_id: pat_id,
|
||||
kind: hir::PatKind::Binding(hir::BindingAnnotation::NONE, pat_id, Ident::empty(), None),
|
||||
span: ty.span,
|
||||
default_binding_modes: false,
|
||||
});
|
||||
|
||||
(hir::Param { hir_id: self.next_id(), pat, ty_span: ty.span, span: ty.span }, pat_node_id)
|
||||
}
|
||||
|
||||
fn generate_arg(&mut self, ty: &'hir hir::Ty<'hir>, param_id: HirId) -> hir::Expr<'hir> {
|
||||
let segments = self.arena.alloc_from_iter(iter::once(hir::PathSegment {
|
||||
ident: Ident::empty(),
|
||||
hir_id: self.next_id(),
|
||||
res: Res::Local(param_id),
|
||||
args: None,
|
||||
infer_args: false,
|
||||
}));
|
||||
|
||||
let path =
|
||||
self.arena.alloc(hir::Path { span: ty.span, res: Res::Local(param_id), segments });
|
||||
|
||||
hir::Expr {
|
||||
hir_id: self.next_id(),
|
||||
kind: hir::ExprKind::Path(hir::QPath::Resolved(None, path)),
|
||||
span: ty.span,
|
||||
}
|
||||
}
|
||||
|
||||
fn lower_delegation_body(
|
||||
&mut self,
|
||||
decl: &'hir hir::FnDecl<'hir>,
|
||||
delegation: &Delegation,
|
||||
) -> BodyId {
|
||||
let path = self.lower_qpath(
|
||||
delegation.id,
|
||||
&delegation.qself,
|
||||
&delegation.path,
|
||||
ParamMode::Optional,
|
||||
&ImplTraitContext::Disallowed(ImplTraitPosition::Path),
|
||||
None,
|
||||
);
|
||||
let block = delegation.body.as_deref();
|
||||
|
||||
self.lower_body(|this| {
|
||||
let mut parameters: Vec<hir::Param<'_>> = Vec::new();
|
||||
let mut args: Vec<hir::Expr<'hir>> = Vec::new();
|
||||
|
||||
for (idx, param_ty) in decl.inputs.iter().enumerate() {
|
||||
let (param, pat_node_id) = this.generate_param(param_ty);
|
||||
parameters.push(param);
|
||||
|
||||
let arg = if let Some(block) = block
|
||||
&& idx == 0
|
||||
{
|
||||
let mut self_resolver = SelfResolver {
|
||||
resolver: this.resolver,
|
||||
path_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: block.span,
|
||||
}
|
||||
} else {
|
||||
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);
|
||||
let final_expr = this.generate_call(path, args);
|
||||
(this.arena.alloc_from_iter(parameters), final_expr)
|
||||
})
|
||||
}
|
||||
|
||||
fn generate_call(
|
||||
&mut self,
|
||||
path: hir::QPath<'hir>,
|
||||
args: &'hir [hir::Expr<'hir>],
|
||||
) -> hir::Expr<'hir> {
|
||||
let callee = self.arena.alloc(hir::Expr {
|
||||
hir_id: self.next_id(),
|
||||
kind: hir::ExprKind::Path(path),
|
||||
span: path.span(),
|
||||
});
|
||||
|
||||
let expr = self.arena.alloc(hir::Expr {
|
||||
hir_id: self.next_id(),
|
||||
kind: hir::ExprKind::Call(callee, args),
|
||||
span: path.span(),
|
||||
});
|
||||
|
||||
let block = self.arena.alloc(hir::Block {
|
||||
stmts: &[],
|
||||
expr: Some(expr),
|
||||
hir_id: self.next_id(),
|
||||
rules: hir::BlockCheckMode::DefaultBlock,
|
||||
span: path.span(),
|
||||
targeted_by_break: false,
|
||||
});
|
||||
|
||||
hir::Expr {
|
||||
hir_id: self.next_id(),
|
||||
kind: hir::ExprKind::Block(block, None),
|
||||
span: path.span(),
|
||||
}
|
||||
}
|
||||
|
||||
fn generate_delegation_error(
|
||||
&mut self,
|
||||
err: ErrorGuaranteed,
|
||||
span: Span,
|
||||
) -> DelegationResults<'hir> {
|
||||
let generics = self.lower_delegation_generics(span);
|
||||
|
||||
let decl = self.arena.alloc(hir::FnDecl {
|
||||
inputs: &[],
|
||||
output: hir::FnRetTy::DefaultReturn(span),
|
||||
c_variadic: false,
|
||||
lifetime_elision_allowed: true,
|
||||
implicit_self: hir::ImplicitSelfKind::None,
|
||||
});
|
||||
|
||||
let sig = self.lower_delegation_sig(span, decl);
|
||||
let body_id = self.lower_body(|this| {
|
||||
let expr =
|
||||
hir::Expr { hir_id: this.next_id(), kind: hir::ExprKind::Err(err), span: span };
|
||||
(&[], expr)
|
||||
});
|
||||
DelegationResults { generics, body_id, sig }
|
||||
}
|
||||
}
|
||||
|
||||
struct SelfResolver<'a> {
|
||||
resolver: &'a mut ResolverAstLowering,
|
||||
path_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(sig_id)) = res.full_res()
|
||||
&& sig_id == self.path_id
|
||||
{
|
||||
let new_res = PartialRes::new(Res::Local(self.self_param_id));
|
||||
self.resolver.partial_res_map.insert(id, new_res);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'ast, 'a> Visitor<'ast> for SelfResolver<'a> {
|
||||
fn visit_path(&mut self, path: &'ast Path, id: NodeId) {
|
||||
self.try_replace_id(id);
|
||||
visit::walk_path(self, path);
|
||||
}
|
||||
|
||||
fn visit_path_segment(&mut self, seg: &'ast PathSegment) {
|
||||
self.try_replace_id(seg.id);
|
||||
visit::walk_path_segment(self, seg);
|
||||
}
|
||||
}
|
@ -441,6 +441,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) => {
|
||||
let delegation_results = self.lower_delegation(delegation, id);
|
||||
hir::ItemKind::Fn(
|
||||
delegation_results.sig,
|
||||
delegation_results.generics,
|
||||
delegation_results.body_id,
|
||||
)
|
||||
}
|
||||
ItemKind::MacCall(..) => {
|
||||
panic!("`TyMac` should have been expanded by now")
|
||||
}
|
||||
@ -805,6 +813,14 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
);
|
||||
(generics, kind, ty.is_some())
|
||||
}
|
||||
AssocItemKind::Delegation(box delegation) => {
|
||||
let delegation_results = self.lower_delegation(delegation, i.id);
|
||||
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"),
|
||||
};
|
||||
|
||||
@ -826,6 +842,9 @@ 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(i.id, delegation.id, i.span),
|
||||
},
|
||||
AssocItemKind::MacCall(..) => unimplemented!(),
|
||||
};
|
||||
let id = hir::TraitItemId { owner_id: hir::OwnerId { def_id: self.local_def_id(i.id) } };
|
||||
@ -908,6 +927,13 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
},
|
||||
)
|
||||
}
|
||||
AssocItemKind::Delegation(box delegation) => {
|
||||
let delegation_results = self.lower_delegation(delegation, i.id);
|
||||
(
|
||||
delegation_results.generics,
|
||||
hir::ImplItemKind::Fn(delegation_results.sig, delegation_results.body_id),
|
||||
)
|
||||
}
|
||||
AssocItemKind::MacCall(..) => panic!("`TyMac` should have been expanded by now"),
|
||||
};
|
||||
|
||||
@ -924,6 +950,13 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
}
|
||||
|
||||
fn lower_impl_item_ref(&mut self, i: &AssocItem) -> hir::ImplItemRef {
|
||||
let trait_item_def_id = self
|
||||
.resolver
|
||||
.get_partial_res(i.id)
|
||||
.map(|r| r.expect_full_res().opt_def_id())
|
||||
.unwrap_or(None);
|
||||
self.is_in_trait_impl = trait_item_def_id.is_some();
|
||||
|
||||
hir::ImplItemRef {
|
||||
id: hir::ImplItemId { owner_id: hir::OwnerId { def_id: self.local_def_id(i.id) } },
|
||||
ident: self.lower_ident(i.ident),
|
||||
@ -934,12 +967,12 @@ 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(i.id, delegation.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()),
|
||||
trait_item_def_id,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -77,6 +77,7 @@ macro_rules! arena_vec {
|
||||
|
||||
mod asm;
|
||||
mod block;
|
||||
mod delegation;
|
||||
mod errors;
|
||||
mod expr;
|
||||
mod format;
|
||||
|
@ -556,6 +556,7 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) {
|
||||
gate_all!(explicit_tail_calls, "`become` expression is experimental");
|
||||
gate_all!(generic_const_items, "generic const items are experimental");
|
||||
gate_all!(unnamed_fields, "unnamed fields are not yet fully implemented");
|
||||
gate_all!(fn_delegation, "functions delegation is not yet fully implemented");
|
||||
|
||||
if !visitor.features.never_patterns {
|
||||
if let Some(spans) = spans.get(&sym::never_patterns) {
|
||||
|
@ -376,6 +376,9 @@ impl<'a> State<'a> {
|
||||
state.print_visibility(&item.vis)
|
||||
});
|
||||
}
|
||||
ast::ItemKind::Delegation(box delegation) => {
|
||||
self.print_delegation(delegation, &item.vis, &item.attrs)
|
||||
}
|
||||
}
|
||||
self.ann.post(self, AnnNode::Item(item))
|
||||
}
|
||||
@ -554,10 +557,38 @@ impl<'a> State<'a> {
|
||||
self.word(";");
|
||||
}
|
||||
}
|
||||
ast::AssocItemKind::Delegation(box delegation) => {
|
||||
self.print_delegation(delegation, vis, &item.attrs)
|
||||
}
|
||||
}
|
||||
self.ann.post(self, AnnNode::SubItem(id))
|
||||
}
|
||||
|
||||
pub(crate) fn print_delegation(
|
||||
&mut self,
|
||||
delegation: &ast::Delegation,
|
||||
vis: &ast::Visibility,
|
||||
attrs: &[ast::Attribute],
|
||||
) {
|
||||
if delegation.body.is_some() {
|
||||
self.head("");
|
||||
}
|
||||
self.print_visibility(vis);
|
||||
self.word_space("reuse");
|
||||
|
||||
if let Some(qself) = &delegation.qself {
|
||||
self.print_qpath(&delegation.path, qself, false);
|
||||
} else {
|
||||
self.print_path(&delegation.path, false, 0);
|
||||
}
|
||||
if let Some(body) = &delegation.body {
|
||||
self.nbsp();
|
||||
self.print_block_with_attrs(body, attrs);
|
||||
} else {
|
||||
self.word(";");
|
||||
}
|
||||
}
|
||||
|
||||
fn print_fn_full(
|
||||
&mut self,
|
||||
sig: &ast::FnSig,
|
||||
|
@ -2571,9 +2571,17 @@ pub enum OpaqueTyOrigin {
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, HashStable_Generic)]
|
||||
pub enum InferDelegationKind {
|
||||
Input(usize),
|
||||
Output,
|
||||
}
|
||||
|
||||
/// The various kinds of types recognized by the compiler.
|
||||
#[derive(Debug, Clone, Copy, HashStable_Generic)]
|
||||
pub enum TyKind<'hir> {
|
||||
/// 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]`).
|
||||
|
@ -856,7 +856,7 @@ pub fn walk_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty<'v>) {
|
||||
visitor.visit_lifetime(lifetime);
|
||||
}
|
||||
TyKind::Typeof(ref expression) => visitor.visit_anon_const(expression),
|
||||
TyKind::Infer | TyKind::Err(_) => {}
|
||||
TyKind::Infer | TyKind::InferDelegation(..) | TyKind::Err(_) => {}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -263,6 +263,10 @@ 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_arbitrary = only traits defined in the current crate can be implemented for arbitrary types
|
||||
|
||||
hir_analysis_only_current_traits_foreign = this is not defined in the current crate because this is a foreign trait
|
||||
|
@ -29,10 +29,9 @@ use rustc_hir::{GenericArg, GenericArgs, OpaqueTyOrigin};
|
||||
use rustc_infer::infer::{InferCtxt, TyCtxtInferExt};
|
||||
use rustc_infer::traits::ObligationCause;
|
||||
use rustc_middle::middle::stability::AllowUnstable;
|
||||
use rustc_middle::ty::GenericParamDefKind;
|
||||
use rustc_middle::ty::{
|
||||
self, Const, GenericArgKind, GenericArgsRef, IsSuggestable, ParamEnv, Ty, TyCtxt,
|
||||
TypeVisitableExt,
|
||||
self, Const, GenericArgKind, GenericArgsRef, GenericParamDefKind, IsSuggestable, ParamEnv, Ty,
|
||||
TyCtxt, TypeVisitableExt,
|
||||
};
|
||||
use rustc_session::lint::builtin::AMBIGUOUS_ASSOCIATED_ITEMS;
|
||||
use rustc_span::edit_distance::find_best_match_for_name;
|
||||
@ -2322,6 +2321,114 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
||||
self.ast_ty_to_ty_inner(ast_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 = self.tcx().fn_sig(sig_id).instantiate_identity();
|
||||
if sig.output().has_opaque_types() {
|
||||
try_emit("delegation to a function with opaque type");
|
||||
}
|
||||
|
||||
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");
|
||||
}
|
||||
|
||||
if self.tcx().asyncness(sig_id) == ty::Asyncness::Yes {
|
||||
try_emit("delegation to async functions");
|
||||
}
|
||||
|
||||
if self.tcx().constness(sig_id) == hir::Constness::Const {
|
||||
try_emit("delegation to const functions");
|
||||
}
|
||||
|
||||
if sig.c_variadic() {
|
||||
try_emit("delegation to variadic functions");
|
||||
// variadic functions are also `unsafe` and `extern "C"`.
|
||||
// Do not emit same error multiple times.
|
||||
return error_occured;
|
||||
}
|
||||
|
||||
if let hir::Unsafety::Unsafe = sig.unsafety() {
|
||||
try_emit("delegation to unsafe functions");
|
||||
}
|
||||
|
||||
if abi::Abi::Rust != sig.abi() {
|
||||
try_emit("delegation to non Rust ABI functions");
|
||||
}
|
||||
|
||||
error_occured
|
||||
}
|
||||
|
||||
fn ty_from_delegation(
|
||||
&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 substs = self.tcx().mk_args_from_iter(std::iter::once(generic_self_ty));
|
||||
sig.instantiate(self.tcx(), substs)
|
||||
} else {
|
||||
sig.instantiate_identity()
|
||||
};
|
||||
|
||||
// Bound vars are also inherited from `sig_id`. They will be
|
||||
// rebinded later in `ty_of_fn`.
|
||||
let sig = sig.skip_binder();
|
||||
|
||||
match idx {
|
||||
hir::InferDelegationKind::Input(id) => sig.inputs()[id],
|
||||
hir::InferDelegationKind::Output => sig.output(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Turns a `hir::Ty` into a `Ty`. For diagnostics' purposes we keep track of whether trait
|
||||
/// objects are borrowed like `&dyn Trait` to avoid emitting redundant errors.
|
||||
#[instrument(level = "debug", skip(self), ret)]
|
||||
@ -2329,6 +2436,9 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
||||
let tcx = self.tcx();
|
||||
|
||||
let result_ty = match &ast_ty.kind {
|
||||
hir::TyKind::InferDelegation(sig_id, idx) => {
|
||||
self.ty_from_delegation(*sig_id, *idx, ast_ty.span)
|
||||
}
|
||||
hir::TyKind::Slice(ty) => Ty::new_slice(tcx, self.ast_ty_to_ty(ty)),
|
||||
hir::TyKind::Ptr(mt) => {
|
||||
Ty::new_ptr(tcx, ty::TypeAndMut { ty: self.ast_ty_to_ty(mt.ty), mutbl: mt.mutbl })
|
||||
@ -2520,7 +2630,13 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
||||
hir_ty: Option<&hir::Ty<'_>>,
|
||||
) -> ty::PolyFnSig<'tcx> {
|
||||
let tcx = self.tcx();
|
||||
let bound_vars = tcx.late_bound_vars(hir_id);
|
||||
let bound_vars = if let hir::FnRetTy::Return(ret_ty) = decl.output
|
||||
&& let hir::TyKind::InferDelegation(sig_id, _) = ret_ty.kind
|
||||
{
|
||||
tcx.fn_sig(sig_id).skip_binder().bound_vars()
|
||||
} else {
|
||||
tcx.late_bound_vars(hir_id)
|
||||
};
|
||||
debug!(?bound_vars);
|
||||
|
||||
// We proactively collect all the inferred type params to emit a single error per fn def.
|
||||
|
@ -1501,3 +1501,13 @@ pub enum RefOfMutStaticSugg {
|
||||
var: String,
|
||||
},
|
||||
}
|
||||
|
||||
#[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,
|
||||
}
|
||||
|
@ -320,7 +320,7 @@ impl<'a> State<'a> {
|
||||
self.word("/*ERROR*/");
|
||||
self.pclose();
|
||||
}
|
||||
hir::TyKind::Infer => {
|
||||
hir::TyKind::Infer | hir::TyKind::InferDelegation(..) => {
|
||||
self.word("_");
|
||||
}
|
||||
}
|
||||
|
@ -42,7 +42,7 @@ use rustc_data_structures::unord::UnordMap;
|
||||
use rustc_errors::{DiagnosticBuilder, ErrorGuaranteed, StashKey};
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def::{CtorKind, CtorOf, DefKind, DocLinkResMap, LifetimeRes, Res};
|
||||
use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, LocalDefId, LocalDefIdMap};
|
||||
use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, LocalDefId, LocalDefIdMap, LocalDefIdSet};
|
||||
use rustc_index::IndexVec;
|
||||
use rustc_macros::HashStable;
|
||||
use rustc_query_system::ich::StableHashingContext;
|
||||
@ -202,6 +202,10 @@ pub struct ResolverAstLowering {
|
||||
|
||||
/// Lints that were emitted by the resolver and early lints.
|
||||
pub lint_buffer: Steal<LintBuffer>,
|
||||
|
||||
/// Information about functions signatures for delegation items expansion
|
||||
pub has_self: LocalDefIdSet,
|
||||
pub fn_parameter_counts: LocalDefIdMap<usize>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
|
@ -252,6 +252,8 @@ impl<'a> Parser<'a> {
|
||||
{
|
||||
// IMPL ITEM
|
||||
self.parse_item_impl(attrs, def_())?
|
||||
} 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])
|
||||
{
|
||||
@ -349,11 +351,18 @@ impl<'a> Parser<'a> {
|
||||
/// When parsing a statement, would the start of a path be an item?
|
||||
pub(super) fn is_path_start_item(&mut self) -> bool {
|
||||
self.is_kw_followed_by_ident(kw::Union) // no: `union::b`, yes: `union U { .. }`
|
||||
|| self.is_reuse_path_item()
|
||||
|| self.check_auto_or_unsafe_trait_item() // no: `auto::b`, yes: `auto trait X { .. }`
|
||||
|| self.is_async_fn() // no(2015): `async::b`, yes: `async fn`
|
||||
|| matches!(self.is_macro_rules_item(), IsMacroRulesItem::Yes{..}) // no: `macro_rules::b`, yes: `macro_rules! mac`
|
||||
}
|
||||
|
||||
fn is_reuse_path_item(&mut self) -> bool {
|
||||
// no: `reuse ::path` for compatibility reasons with macro invocations
|
||||
self.token.is_keyword(kw::Reuse)
|
||||
&& self.look_ahead(1, |t| t.is_path_start() && t.kind != token::ModSep)
|
||||
}
|
||||
|
||||
/// Are we sure this could not possibly be a macro invocation?
|
||||
fn isnt_macro_invocation(&mut self) -> bool {
|
||||
self.check_ident() && self.look_ahead(1, |t| *t != token::Not && *t != token::ModSep)
|
||||
@ -655,6 +664,33 @@ impl<'a> Parser<'a> {
|
||||
Ok((Ident::empty(), item_kind))
|
||||
}
|
||||
|
||||
fn parse_item_delegation(&mut self) -> PResult<'a, ItemInfo> {
|
||||
let span = self.token.span;
|
||||
self.expect_keyword(kw::Reuse)?;
|
||||
|
||||
let (qself, path) = if self.eat_lt() {
|
||||
let (qself, path) = self.parse_qpath(PathStyle::Expr)?;
|
||||
(Some(qself), path)
|
||||
} else {
|
||||
(None, self.parse_path(PathStyle::Expr)?)
|
||||
};
|
||||
|
||||
let body = if self.check(&token::OpenDelim(Delimiter::Brace)) {
|
||||
Some(self.parse_block()?)
|
||||
} else {
|
||||
self.expect(&token::Semi)?;
|
||||
None
|
||||
};
|
||||
let span = span.to(self.prev_token.span);
|
||||
self.sess.gated_spans.gate(sym::fn_delegation, span);
|
||||
|
||||
let ident = path.segments.last().map(|seg| seg.ident).unwrap_or(Ident::empty());
|
||||
Ok((
|
||||
ident,
|
||||
ItemKind::Delegation(Box::new(Delegation { id: DUMMY_NODE_ID, qself, path, body })),
|
||||
))
|
||||
}
|
||||
|
||||
fn parse_item_list<T>(
|
||||
&mut self,
|
||||
attrs: &mut AttrVec,
|
||||
|
@ -341,6 +341,7 @@ impl<'v> hir_visit::Visitor<'v> for StatCollector<'v> {
|
||||
record_variants!(
|
||||
(self, t, t.kind, Id::Node(t.hir_id), hir, Ty, TyKind),
|
||||
[
|
||||
InferDelegation,
|
||||
Slice,
|
||||
Array,
|
||||
Ptr,
|
||||
@ -521,7 +522,8 @@ impl<'v> ast_visit::Visitor<'v> for StatCollector<'v> {
|
||||
TraitAlias,
|
||||
Impl,
|
||||
MacCall,
|
||||
MacroDef
|
||||
MacroDef,
|
||||
Delegation
|
||||
]
|
||||
);
|
||||
ast_visit::walk_item(self, i)
|
||||
@ -645,7 +647,7 @@ impl<'v> ast_visit::Visitor<'v> for StatCollector<'v> {
|
||||
fn visit_assoc_item(&mut self, i: &'v ast::AssocItem, ctxt: ast_visit::AssocCtxt) {
|
||||
record_variants!(
|
||||
(self, i, i.kind, Id::None, ast, AssocItem, AssocItemKind),
|
||||
[Const, Fn, Type, MacCall]
|
||||
[Const, Fn, Type, MacCall, Delegation]
|
||||
);
|
||||
ast_visit::walk_assoc_item(self, i, ctxt);
|
||||
}
|
||||
|
@ -271,7 +271,7 @@ impl<'ast, 'tcx> visit::Visitor<'ast> for LanguageItemCollector<'ast, 'tcx> {
|
||||
ast::ItemKind::Use(_) => Target::Use,
|
||||
ast::ItemKind::Static(_) => Target::Static,
|
||||
ast::ItemKind::Const(_) => Target::Const,
|
||||
ast::ItemKind::Fn(_) => Target::Fn,
|
||||
ast::ItemKind::Fn(_) | ast::ItemKind::Delegation(..) => Target::Fn,
|
||||
ast::ItemKind::Mod(_, _) => Target::Mod,
|
||||
ast::ItemKind::ForeignMod(_) => Target::ForeignFn,
|
||||
ast::ItemKind::GlobalAsm(_) => Target::GlobalAsm,
|
||||
@ -315,24 +315,29 @@ impl<'ast, 'tcx> visit::Visitor<'ast> for LanguageItemCollector<'ast, 'tcx> {
|
||||
|
||||
fn visit_assoc_item(&mut self, i: &'ast ast::AssocItem, ctxt: visit::AssocCtxt) {
|
||||
let (target, generics) = match &i.kind {
|
||||
ast::AssocItemKind::Fn(fun) => (
|
||||
match &self.parent_item.unwrap().kind {
|
||||
ast::ItemKind::Impl(i) => {
|
||||
if i.of_trait.is_some() {
|
||||
Target::Method(MethodKind::Trait { body: fun.body.is_some() })
|
||||
} else {
|
||||
Target::Method(MethodKind::Inherent)
|
||||
ast::AssocItemKind::Fn(..) | ast::AssocItemKind::Delegation(..) => {
|
||||
let (body, generics) = if let ast::AssocItemKind::Fn(fun) = &i.kind {
|
||||
(fun.body.is_some(), Some(&fun.generics))
|
||||
} else {
|
||||
(true, None)
|
||||
};
|
||||
(
|
||||
match &self.parent_item.unwrap().kind {
|
||||
ast::ItemKind::Impl(i) => {
|
||||
if i.of_trait.is_some() {
|
||||
Target::Method(MethodKind::Trait { body })
|
||||
} else {
|
||||
Target::Method(MethodKind::Inherent)
|
||||
}
|
||||
}
|
||||
}
|
||||
ast::ItemKind::Trait(_) => {
|
||||
Target::Method(MethodKind::Trait { body: fun.body.is_some() })
|
||||
}
|
||||
_ => unreachable!(),
|
||||
},
|
||||
&fun.generics,
|
||||
),
|
||||
ast::AssocItemKind::Const(ct) => (Target::AssocConst, &ct.generics),
|
||||
ast::AssocItemKind::Type(ty) => (Target::AssocTy, &ty.generics),
|
||||
ast::ItemKind::Trait(_) => Target::Method(MethodKind::Trait { body }),
|
||||
_ => unreachable!(),
|
||||
},
|
||||
generics,
|
||||
)
|
||||
}
|
||||
ast::AssocItemKind::Const(ct) => (Target::AssocConst, Some(&ct.generics)),
|
||||
ast::AssocItemKind::Type(ty) => (Target::AssocTy, Some(&ty.generics)),
|
||||
ast::AssocItemKind::MacCall(_) => unreachable!("macros should have been expanded"),
|
||||
};
|
||||
|
||||
@ -341,7 +346,7 @@ impl<'ast, 'tcx> visit::Visitor<'ast> for LanguageItemCollector<'ast, 'tcx> {
|
||||
self.resolver.node_id_to_def_id[&i.id],
|
||||
&i.attrs,
|
||||
i.span,
|
||||
Some(generics),
|
||||
generics,
|
||||
);
|
||||
|
||||
visit::walk_assoc_item(self, i, ctxt);
|
||||
|
@ -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_code_err, Applicability};
|
||||
@ -686,10 +686,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(..) => {
|
||||
@ -701,11 +698,11 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> {
|
||||
}
|
||||
|
||||
// These items live in the type namespace.
|
||||
ItemKind::TyAlias(..) => {
|
||||
ItemKind::TyAlias(..) | ItemKind::TraitAlias(..) => {
|
||||
self.r.define(parent, ident, TypeNS, (res, vis, sp, expansion));
|
||||
}
|
||||
|
||||
ItemKind::Enum(_, _) => {
|
||||
ItemKind::Enum(_, _) | ItemKind::Trait(..) => {
|
||||
let module = self.r.new_module(
|
||||
Some(parent),
|
||||
ModuleKind::Def(def_kind, def_id, ident.name),
|
||||
@ -717,10 +714,6 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> {
|
||||
self.parent_scope.module = module;
|
||||
}
|
||||
|
||||
ItemKind::TraitAlias(..) => {
|
||||
self.r.define(parent, ident, TypeNS, (res, vis, sp, expansion));
|
||||
}
|
||||
|
||||
// These items live in both the type and value namespaces.
|
||||
ItemKind::Struct(ref vdata, _) => {
|
||||
// Define a name in the type namespace.
|
||||
@ -778,19 +771,6 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> {
|
||||
self.insert_field_visibilities_local(def_id, vdata);
|
||||
}
|
||||
|
||||
ItemKind::Trait(..) => {
|
||||
// Add all the items within to a new module.
|
||||
let module = self.r.new_module(
|
||||
Some(parent),
|
||||
ModuleKind::Def(def_kind, def_id, ident.name),
|
||||
expansion.to_expn_id(),
|
||||
item.span,
|
||||
parent.no_implicit_prelude,
|
||||
);
|
||||
self.r.define(parent, ident, TypeNS, (module, vis, sp, expansion));
|
||||
self.parent_scope.module = module;
|
||||
}
|
||||
|
||||
// These items do not add names to modules.
|
||||
ItemKind::Impl(box Impl { of_trait: Some(..), .. }) => {
|
||||
self.r.trait_impl_items.insert(local_def_id);
|
||||
@ -1358,13 +1338,9 @@ 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::MacCall(_) => bug!(), // handled above
|
||||
};
|
||||
|
@ -111,7 +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::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();
|
||||
@ -259,7 +259,7 @@ 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::MacCall(..) => return self.visit_macro_invoc(i.id),
|
||||
|
@ -277,7 +277,8 @@ impl<'r, 'ast, 'tcx> Visitor<'ast> for EffectiveVisibilitiesVisitor<'ast, 'r, 't
|
||||
| ast::ItemKind::TraitAlias(..)
|
||||
| ast::ItemKind::MacroDef(..)
|
||||
| ast::ItemKind::ForeignMod(..)
|
||||
| ast::ItemKind::Fn(..) => return,
|
||||
| ast::ItemKind::Fn(..)
|
||||
| ast::ItemKind::Delegation(..) => return,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -394,13 +394,18 @@ pub(crate) enum PathSource<'a> {
|
||||
TupleStruct(Span, &'a [Span]),
|
||||
// `m::A::B` in `<T as m::A>::B::C`.
|
||||
TraitItem(Namespace),
|
||||
// Paths in delegation item
|
||||
Delegation,
|
||||
}
|
||||
|
||||
impl<'a> PathSource<'a> {
|
||||
fn namespace(self) -> Namespace {
|
||||
match self {
|
||||
PathSource::Type | PathSource::Trait(_) | PathSource::Struct => TypeNS,
|
||||
PathSource::Expr(..) | PathSource::Pat | PathSource::TupleStruct(..) => ValueNS,
|
||||
PathSource::Expr(..)
|
||||
| PathSource::Pat
|
||||
| PathSource::TupleStruct(..)
|
||||
| PathSource::Delegation => ValueNS,
|
||||
PathSource::TraitItem(ns) => ns,
|
||||
}
|
||||
}
|
||||
@ -412,7 +417,7 @@ impl<'a> PathSource<'a> {
|
||||
| PathSource::Pat
|
||||
| PathSource::Struct
|
||||
| PathSource::TupleStruct(..) => true,
|
||||
PathSource::Trait(_) | PathSource::TraitItem(..) => false,
|
||||
PathSource::Trait(_) | PathSource::TraitItem(..) | PathSource::Delegation => false,
|
||||
}
|
||||
}
|
||||
|
||||
@ -454,6 +459,7 @@ impl<'a> PathSource<'a> {
|
||||
},
|
||||
_ => "value",
|
||||
},
|
||||
PathSource::Delegation => "function",
|
||||
}
|
||||
}
|
||||
|
||||
@ -521,6 +527,7 @@ impl<'a> PathSource<'a> {
|
||||
Res::Def(DefKind::AssocTy, _) if ns == TypeNS => true,
|
||||
_ => false,
|
||||
},
|
||||
PathSource::Delegation => matches!(res, Res::Def(DefKind::Fn | DefKind::AssocFn, _)),
|
||||
}
|
||||
}
|
||||
|
||||
@ -533,8 +540,8 @@ 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),
|
||||
@ -1805,7 +1812,8 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
|
||||
PathSource::Expr(..)
|
||||
| PathSource::Pat
|
||||
| PathSource::Struct
|
||||
| PathSource::TupleStruct(..) => true,
|
||||
| PathSource::TupleStruct(..)
|
||||
| PathSource::Delegation => true,
|
||||
};
|
||||
if inferred {
|
||||
// Do not create a parameter for patterns and expressions: type checking can infer
|
||||
@ -2514,6 +2522,10 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
|
||||
visit::walk_item(self, item);
|
||||
}
|
||||
|
||||
ItemKind::Delegation(ref delegation) => {
|
||||
self.resolve_delegation(delegation);
|
||||
}
|
||||
|
||||
ItemKind::ExternCrate(..) => {}
|
||||
|
||||
ItemKind::MacCall(_) => panic!("unexpanded macro in resolve!"),
|
||||
@ -2790,6 +2802,9 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
|
||||
AssocItemKind::Fn(box Fn { generics, .. }) => {
|
||||
walk_assoc_item(self, generics, LifetimeBinderKind::Function, item);
|
||||
}
|
||||
AssocItemKind::Delegation(delegation) => {
|
||||
self.resolve_delegation(delegation);
|
||||
}
|
||||
AssocItemKind::Type(box TyAlias { generics, .. }) => self
|
||||
.with_lifetime_rib(LifetimeRibKind::AnonymousReportError, |this| {
|
||||
walk_assoc_item(this, generics, LifetimeBinderKind::Item, item)
|
||||
@ -3036,6 +3051,19 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
|
||||
},
|
||||
);
|
||||
}
|
||||
AssocItemKind::Delegation(box delegation) => {
|
||||
debug!("resolve_implementation AssocItemKind::Delegation");
|
||||
self.check_trait_item(
|
||||
item.id,
|
||||
item.ident,
|
||||
&item.kind,
|
||||
ValueNS,
|
||||
item.span,
|
||||
seen_trait_items,
|
||||
|i, s, c| MethodNotMemberOfTrait(i, s, c),
|
||||
);
|
||||
self.resolve_delegation(delegation);
|
||||
}
|
||||
AssocItemKind::MacCall(_) => {
|
||||
panic!("unexpanded macro in resolve!")
|
||||
}
|
||||
@ -3123,7 +3151,8 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
|
||||
match (def_kind, kind) {
|
||||
(DefKind::AssocTy, AssocItemKind::Type(..))
|
||||
| (DefKind::AssocFn, AssocItemKind::Fn(..))
|
||||
| (DefKind::AssocConst, AssocItemKind::Const(..)) => {
|
||||
| (DefKind::AssocConst, AssocItemKind::Const(..))
|
||||
| (DefKind::AssocFn, AssocItemKind::Delegation(..)) => {
|
||||
self.r.record_partial_res(id, PartialRes::new(res));
|
||||
return;
|
||||
}
|
||||
@ -3136,6 +3165,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
|
||||
AssocItemKind::Const(..) => (rustc_errors::error_code!(E0323), "const"),
|
||||
AssocItemKind::Fn(..) => (rustc_errors::error_code!(E0324), "method"),
|
||||
AssocItemKind::Type(..) => (rustc_errors::error_code!(E0325), "type"),
|
||||
AssocItemKind::Delegation(..) => (rustc_errors::error_code!(E0324), "method"),
|
||||
AssocItemKind::MacCall(..) => span_bug!(span, "unexpanded macro"),
|
||||
};
|
||||
let trait_path = path_names_to_string(path);
|
||||
@ -3159,6 +3189,32 @@ 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);
|
||||
if let Some(body) = &delegation.body {
|
||||
// `PatBoundCtx` is not necessary in this context
|
||||
let mut bindings = smallvec![(PatBoundCtx::Product, Default::default())];
|
||||
|
||||
let span = delegation.path.segments.last().unwrap().ident.span;
|
||||
self.fresh_binding(
|
||||
Ident::new(kw::SelfLower, span),
|
||||
delegation.id,
|
||||
PatternSource::FnParam,
|
||||
&mut bindings,
|
||||
);
|
||||
self.visit_block(body);
|
||||
}
|
||||
}
|
||||
|
||||
fn resolve_params(&mut self, params: &'ast [Param]) {
|
||||
let mut bindings = smallvec![(PatBoundCtx::Product, Default::default())];
|
||||
self.with_lifetime_rib(LifetimeRibKind::Elided(LifetimeRes::Infer), |this| {
|
||||
@ -4551,13 +4607,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 def_id = self.r.local_def_id(id);
|
||||
self.r.fn_parameter_counts.insert(def_id, sig.decl.inputs.len());
|
||||
|
||||
if sig.decl.has_self() {
|
||||
self.r.has_self.insert(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, .. })
|
||||
@ -4569,6 +4636,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
|
||||
@ -4586,14 +4657,27 @@ impl<'ast> Visitor<'ast> for LifetimeCountVisitor<'_, '_, '_> {
|
||||
| ItemKind::MacroDef(..)
|
||||
| ItemKind::GlobalAsm(..)
|
||||
| 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);
|
||||
|
@ -656,7 +656,10 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
|
||||
let typo_sugg = self
|
||||
.lookup_typo_candidate(path, following_seg, source.namespace(), is_expected)
|
||||
.to_opt_suggestion();
|
||||
if path.len() == 1 && self.self_type_is_available() {
|
||||
if path.len() == 1
|
||||
&& !matches!(source, PathSource::Delegation)
|
||||
&& self.self_type_is_available()
|
||||
{
|
||||
if let Some(candidate) =
|
||||
self.lookup_assoc_candidate(ident, ns, is_expected, source.is_call())
|
||||
{
|
||||
@ -1899,6 +1902,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
|
||||
(AssocItemKind::Const(..), Res::Def(DefKind::AssocConst, _)) => true,
|
||||
(AssocItemKind::Fn(_), Res::Def(DefKind::AssocFn, _)) => true,
|
||||
(AssocItemKind::Type(..), Res::Def(DefKind::AssocTy, _)) => true,
|
||||
(AssocItemKind::Delegation(_), Res::Def(DefKind::AssocFn, _)) => true,
|
||||
_ => false,
|
||||
})
|
||||
.map(|(key, _)| key.ident.name)
|
||||
@ -1960,6 +1964,12 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
|
||||
}
|
||||
ast::AssocItemKind::Fn(..) => AssocSuggestion::AssocFn { called },
|
||||
ast::AssocItemKind::Type(..) => AssocSuggestion::AssocType,
|
||||
ast::AssocItemKind::Delegation(..)
|
||||
if self.r.has_self.contains(&self.r.local_def_id(assoc_item.id)) =>
|
||||
{
|
||||
AssocSuggestion::MethodWithSelf { called }
|
||||
}
|
||||
ast::AssocItemKind::Delegation(..) => AssocSuggestion::AssocFn { called },
|
||||
ast::AssocItemKind::MacCall(_) => continue,
|
||||
});
|
||||
}
|
||||
|
@ -1101,6 +1101,8 @@ pub struct Resolver<'a, 'tcx> {
|
||||
legacy_const_generic_args: FxHashMap<DefId, Option<Vec<usize>>>,
|
||||
/// Amount of lifetime parameters for each item in the crate.
|
||||
item_generics_num_lifetimes: FxHashMap<LocalDefId, usize>,
|
||||
/// Amount of parameters for each function in the crate.
|
||||
fn_parameter_counts: LocalDefIdMap<usize>,
|
||||
|
||||
main_def: Option<MainDefinition>,
|
||||
trait_impls: FxIndexMap<DefId, Vec<LocalDefId>>,
|
||||
@ -1439,6 +1441,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
||||
doc_link_resolutions: Default::default(),
|
||||
doc_link_traits_in_scope: Default::default(),
|
||||
all_macro_rules: Default::default(),
|
||||
fn_parameter_counts: Default::default(),
|
||||
};
|
||||
|
||||
let root_parent_scope = ParentScope::module(graph_root, &resolver);
|
||||
@ -1542,6 +1545,8 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
||||
trait_map: self.trait_map,
|
||||
lifetime_elision_allowed: self.lifetime_elision_allowed,
|
||||
lint_buffer: Steal::new(self.lint_buffer),
|
||||
has_self: self.has_self,
|
||||
fn_parameter_counts: self.fn_parameter_counts,
|
||||
};
|
||||
ResolverOutputs { global_ctxt, ast_lowering }
|
||||
}
|
||||
|
@ -102,6 +102,7 @@ symbols! {
|
||||
Gen: "gen",
|
||||
MacroRules: "macro_rules",
|
||||
Raw: "raw",
|
||||
Reuse: "reuse",
|
||||
Union: "union",
|
||||
Yeet: "yeet",
|
||||
}
|
||||
|
@ -1870,7 +1870,7 @@ pub(crate) fn clean_ty<'tcx>(ty: &hir::Ty<'tcx>, cx: &mut DocContext<'tcx>) -> T
|
||||
}
|
||||
TyKind::BareFn(barefn) => BareFunction(Box::new(clean_bare_fn_ty(barefn, cx))),
|
||||
// Rustdoc handles `TyKind::Err`s by turning them into `Type::Infer`s.
|
||||
TyKind::Infer | TyKind::Err(_) | TyKind::Typeof(..) => Infer,
|
||||
TyKind::Infer | TyKind::Err(_) | TyKind::Typeof(..) | TyKind::InferDelegation(..) => Infer,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -830,6 +830,7 @@ impl TyCoercionStability {
|
||||
| TyKind::Infer
|
||||
| TyKind::Typeof(..)
|
||||
| TyKind::TraitObject(..)
|
||||
| TyKind::InferDelegation(..)
|
||||
| TyKind::Err(_) => Self::Reborrow,
|
||||
};
|
||||
}
|
||||
|
@ -1108,7 +1108,7 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
|
||||
TyKind::Typeof(anon_const) => {
|
||||
self.hash_body(anon_const.body);
|
||||
},
|
||||
TyKind::Err(_) | TyKind::Infer | TyKind::Never => {},
|
||||
TyKind::Err(_) | TyKind::Infer | TyKind::Never | TyKind::InferDelegation(..) => {},
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -728,7 +728,9 @@ impl<'a> FmtVisitor<'a> {
|
||||
(Const(..), Const(..)) | (MacCall(..), MacCall(..)) => {
|
||||
a.ident.as_str().cmp(b.ident.as_str())
|
||||
}
|
||||
(Fn(..), Fn(..)) => a.span.lo().cmp(&b.span.lo()),
|
||||
(Fn(..), Fn(..)) | (Delegation(..), Delegation(..)) => {
|
||||
a.span.lo().cmp(&b.span.lo())
|
||||
}
|
||||
(Type(ty), _) if is_type(&ty.ty) => Ordering::Less,
|
||||
(_, Type(ty)) if is_type(&ty.ty) => Ordering::Greater,
|
||||
(Type(..), _) => Ordering::Less,
|
||||
@ -737,6 +739,8 @@ impl<'a> FmtVisitor<'a> {
|
||||
(_, Const(..)) => Ordering::Greater,
|
||||
(MacCall(..), _) => Ordering::Less,
|
||||
(_, MacCall(..)) => Ordering::Greater,
|
||||
(Delegation(..), _) => Ordering::Less,
|
||||
(_, Delegation(..)) => Ordering::Greater,
|
||||
});
|
||||
let mut prev_kind = None;
|
||||
for (buf, item) in buffer {
|
||||
|
@ -592,6 +592,11 @@ impl<'b, 'a: 'b> FmtVisitor<'a> {
|
||||
);
|
||||
self.push_rewrite(item.span, rewrite);
|
||||
}
|
||||
ast::ItemKind::Delegation(..) => {
|
||||
// TODO: rewrite delegation items once syntax is established.
|
||||
// For now, leave the contents of the Span unformatted.
|
||||
self.push_rewrite(item.span, None)
|
||||
}
|
||||
};
|
||||
}
|
||||
self.skip_context = skip_context_saved;
|
||||
|
@ -11,7 +11,7 @@ use std::path::{Path, PathBuf};
|
||||
const ENTRY_LIMIT: usize = 900;
|
||||
// FIXME: The following limits should be reduced eventually.
|
||||
const ISSUES_ENTRY_LIMIT: usize = 1849;
|
||||
const ROOT_ENTRY_LIMIT: usize = 869;
|
||||
const ROOT_ENTRY_LIMIT: usize = 870;
|
||||
|
||||
const EXPECTED_TEST_FILE_EXTENSIONS: &[&str] = &[
|
||||
"rs", // test source files
|
||||
|
25
tests/pretty/delegation.rs
Normal file
25
tests/pretty/delegation.rs
Normal file
@ -0,0 +1,25 @@
|
||||
#![feature(fn_delegation)]
|
||||
//~^ WARN the feature `fn_delegation` is incomplete
|
||||
|
||||
// pp-exact
|
||||
|
||||
trait Trait {
|
||||
fn bar(&self, x: i32) -> i32 { x }
|
||||
}
|
||||
|
||||
struct F;
|
||||
impl Trait for F {}
|
||||
|
||||
struct S(F);
|
||||
impl Trait for S {
|
||||
reuse Trait::bar { &self.0 }
|
||||
}
|
||||
|
||||
mod to_reuse {
|
||||
pub fn foo() {}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub reuse to_reuse::foo;
|
||||
|
||||
fn main() {}
|
47
tests/ui/delegation/bad-resolve.rs
Normal file
47
tests/ui/delegation/bad-resolve.rs
Normal file
@ -0,0 +1,47 @@
|
||||
#![feature(fn_delegation)]
|
||||
//~^ WARN the feature `fn_delegation` is incomplete
|
||||
|
||||
trait Trait {
|
||||
const C: u32 = 0;
|
||||
type Type;
|
||||
fn bar() {}
|
||||
fn foo(&self, x: i32) -> i32 { x }
|
||||
}
|
||||
|
||||
struct F;
|
||||
impl Trait for F {
|
||||
type Type = i32;
|
||||
}
|
||||
|
||||
impl F {
|
||||
fn foo(&self, x: i32) -> i32 { x }
|
||||
}
|
||||
|
||||
struct S(F);
|
||||
|
||||
impl Trait for S {
|
||||
//~^ ERROR not all trait items implemented, missing: `Type`
|
||||
reuse <F as Trait>::C;
|
||||
//~^ ERROR item `C` is an associated method, which doesn't match its trait `Trait`
|
||||
//~| ERROR expected function, found associated constant `Trait::C`
|
||||
reuse <F as Trait>::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 <F as Trait>::baz;
|
||||
//~^ ERROR method `baz` is not a member of trait `Trait`
|
||||
//~| ERROR cannot find method or associated constant `baz` in trait `Trait`
|
||||
reuse <F as Trait>::bar;
|
||||
|
||||
reuse foo { &self.0 }
|
||||
//~^ ERROR cannot find function `foo` in this scope
|
||||
reuse F::foo { &self.0 }
|
||||
//~^ ERROR cannot find function `foo` in `F`
|
||||
//~| ERROR duplicate definitions with name `foo`
|
||||
}
|
||||
|
||||
impl S {
|
||||
reuse F::foo { &self.0 }
|
||||
//~^ ERROR cannot find function `foo` in `F`
|
||||
}
|
||||
|
||||
fn main() {}
|
102
tests/ui/delegation/bad-resolve.stderr
Normal file
102
tests/ui/delegation/bad-resolve.stderr
Normal file
@ -0,0 +1,102 @@
|
||||
error[E0324]: item `C` is an associated method, which doesn't match its trait `Trait`
|
||||
--> $DIR/bad-resolve.rs:24:5
|
||||
|
|
||||
LL | const C: u32 = 0;
|
||||
| ----------------- item in trait
|
||||
...
|
||||
LL | reuse <F as Trait>::C;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^ does not match trait
|
||||
|
||||
error[E0324]: item `Type` is an associated method, which doesn't match its trait `Trait`
|
||||
--> $DIR/bad-resolve.rs:27:5
|
||||
|
|
||||
LL | type Type;
|
||||
| ---------- item in trait
|
||||
...
|
||||
LL | reuse <F as Trait>::Type;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^ does not match trait
|
||||
|
||||
error[E0407]: method `baz` is not a member of trait `Trait`
|
||||
--> $DIR/bad-resolve.rs:30:5
|
||||
|
|
||||
LL | reuse <F as Trait>::baz;
|
||||
| ^^^^^^^^^^^^^^^^^^^^---^
|
||||
| | |
|
||||
| | help: there is an associated function with a similar name: `bar`
|
||||
| not a member of trait `Trait`
|
||||
|
||||
error[E0201]: duplicate definitions with name `foo`:
|
||||
--> $DIR/bad-resolve.rs:37: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[E0423]: expected function, found associated constant `Trait::C`
|
||||
--> $DIR/bad-resolve.rs:24:11
|
||||
|
|
||||
LL | reuse <F as Trait>::C;
|
||||
| ^^^^^^^^^^^^^^^ not a function
|
||||
|
||||
error[E0575]: expected method or associated constant, found associated type `Trait::Type`
|
||||
--> $DIR/bad-resolve.rs:27:11
|
||||
|
|
||||
LL | reuse <F as Trait>::Type;
|
||||
| ^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: can't use a type alias as a constructor
|
||||
|
||||
error[E0576]: cannot find method or associated constant `baz` in trait `Trait`
|
||||
--> $DIR/bad-resolve.rs:30:25
|
||||
|
|
||||
LL | fn bar() {}
|
||||
| -------- similarly named associated function `bar` defined here
|
||||
...
|
||||
LL | reuse <F as Trait>::baz;
|
||||
| ^^^ help: an associated function with a similar name exists: `bar`
|
||||
|
||||
error[E0425]: cannot find function `foo` in this scope
|
||||
--> $DIR/bad-resolve.rs:35:11
|
||||
|
|
||||
LL | reuse foo { &self.0 }
|
||||
| ^^^ not found in this scope
|
||||
|
||||
error[E0425]: cannot find function `foo` in `F`
|
||||
--> $DIR/bad-resolve.rs:37:14
|
||||
|
|
||||
LL | reuse F::foo { &self.0 }
|
||||
| ^^^ not found in `F`
|
||||
|
||||
error[E0425]: cannot find function `foo` in `F`
|
||||
--> $DIR/bad-resolve.rs:43:14
|
||||
|
|
||||
LL | reuse F::foo { &self.0 }
|
||||
| ^^^ not found in `F`
|
||||
|
||||
warning: the feature `fn_delegation` is incomplete and may not be safe to use and/or cause compiler crashes
|
||||
--> $DIR/bad-resolve.rs:1:12
|
||||
|
|
||||
LL | #![feature(fn_delegation)]
|
||||
| ^^^^^^^^^^^^^
|
||||
|
|
||||
= note: see issue #118212 <https://github.com/rust-lang/rust/issues/118212> for more information
|
||||
= note: `#[warn(incomplete_features)]` on by default
|
||||
|
||||
error[E0046]: not all trait items implemented, missing: `Type`
|
||||
--> $DIR/bad-resolve.rs:22:1
|
||||
|
|
||||
LL | type Type;
|
||||
| --------- `Type` from trait
|
||||
...
|
||||
LL | impl Trait for S {
|
||||
| ^^^^^^^^^^^^^^^^ missing `Type` in implementation
|
||||
|
||||
error: aborting due to 11 previous errors; 1 warning emitted
|
||||
|
||||
Some errors have detailed explanations: E0046, E0201, E0324, E0407, E0423, E0425, E0575, E0576.
|
||||
For more information about an error, try `rustc --explain E0046`.
|
27
tests/ui/delegation/explicit-paths-in-traits-pass.rs
Normal file
27
tests/ui/delegation/explicit-paths-in-traits-pass.rs
Normal file
@ -0,0 +1,27 @@
|
||||
// run-pass
|
||||
|
||||
#![feature(fn_delegation)]
|
||||
//~^ WARN the feature `fn_delegation` is incomplete
|
||||
|
||||
trait ToReuse {
|
||||
fn foo(&self, x: i32) -> i32 { x }
|
||||
fn foo1(x: i32) -> i32 { x }
|
||||
}
|
||||
|
||||
fn foo2() -> i32 { 42 }
|
||||
|
||||
trait Trait: ToReuse {
|
||||
reuse ToReuse::foo;
|
||||
reuse <Self as ToReuse>::foo1;
|
||||
reuse foo2;
|
||||
}
|
||||
|
||||
struct S;
|
||||
impl ToReuse for S {}
|
||||
impl Trait for S {}
|
||||
|
||||
fn main() {
|
||||
assert_eq!(<S as Trait>::foo(&S, 1), 1);
|
||||
assert_eq!(<S as Trait>::foo1(1), 1);
|
||||
assert_eq!(<S as Trait>::foo2(), 42);
|
||||
}
|
11
tests/ui/delegation/explicit-paths-in-traits-pass.stderr
Normal file
11
tests/ui/delegation/explicit-paths-in-traits-pass.stderr
Normal file
@ -0,0 +1,11 @@
|
||||
warning: the feature `fn_delegation` is incomplete and may not be safe to use and/or cause compiler crashes
|
||||
--> $DIR/explicit-paths-in-traits-pass.rs:3:12
|
||||
|
|
||||
LL | #![feature(fn_delegation)]
|
||||
| ^^^^^^^^^^^^^
|
||||
|
|
||||
= note: see issue #118212 <https://github.com/rust-lang/rust/issues/118212> for more information
|
||||
= note: `#[warn(incomplete_features)]` on by default
|
||||
|
||||
warning: 1 warning emitted
|
||||
|
64
tests/ui/delegation/explicit-paths-pass.rs
Normal file
64
tests/ui/delegation/explicit-paths-pass.rs
Normal file
@ -0,0 +1,64 @@
|
||||
// run-pass
|
||||
|
||||
#![feature(fn_delegation)]
|
||||
//~^ WARN the feature `fn_delegation` is incomplete
|
||||
|
||||
trait Trait {
|
||||
fn bar(&self, x: i32) -> i32 { x }
|
||||
fn description(&self) -> &str {
|
||||
"hello world!"
|
||||
}
|
||||
fn static_method(x: i32) -> i32 { x }
|
||||
fn static_method2(x: i32, y: i32) -> i32 { x + y }
|
||||
fn baz<'a>(&self, x: &'a i32) -> &'a i32 { x }
|
||||
}
|
||||
|
||||
struct F;
|
||||
impl Trait for F {}
|
||||
|
||||
mod to_reuse {
|
||||
pub fn foo(x: i32) -> i32 { x + 1 }
|
||||
pub fn zero_args() -> i32 { 15 }
|
||||
}
|
||||
|
||||
reuse to_reuse::zero_args { self }
|
||||
|
||||
struct S(F);
|
||||
impl Trait for S {
|
||||
reuse Trait::bar { &self.0 }
|
||||
reuse Trait::description { &self.0 }
|
||||
reuse <F as Trait>::static_method;
|
||||
reuse <F as Trait>::static_method2 { S::static_method(self) }
|
||||
reuse Trait::baz { &self.0 }
|
||||
}
|
||||
|
||||
impl S {
|
||||
reuse Trait::baz { &self.0 }
|
||||
reuse <F as Trait>::static_method { to_reuse::foo(self) }
|
||||
}
|
||||
|
||||
impl std::fmt::Display for S {
|
||||
reuse <str as std::fmt::Display>::fmt { self.description() }
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let s = S(F);
|
||||
assert_eq!(42, s.bar(42));
|
||||
assert_eq!("hello world!", format!("{s}"));
|
||||
assert_eq!(43, S::static_method(42));
|
||||
assert_eq!(42, <S as Trait>::static_method(42));
|
||||
assert_eq!(21, S::static_method2(10, 10));
|
||||
|
||||
reuse <S as Trait>::static_method;
|
||||
reuse <S as Trait>::static_method2 { static_method(self) }
|
||||
#[inline]
|
||||
reuse to_reuse::foo;
|
||||
assert_eq!(42, static_method(42));
|
||||
assert_eq!(21, static_method2(10, 10));
|
||||
assert_eq!(43, foo(42));
|
||||
assert_eq!(15, zero_args());
|
||||
|
||||
let x: i32 = 15;
|
||||
assert_eq!(&x, <S as Trait>::baz(&s, &x));
|
||||
assert_eq!(&x, S::baz(&s, &x));
|
||||
}
|
11
tests/ui/delegation/explicit-paths-pass.stderr
Normal file
11
tests/ui/delegation/explicit-paths-pass.stderr
Normal file
@ -0,0 +1,11 @@
|
||||
warning: the feature `fn_delegation` is incomplete and may not be safe to use and/or cause compiler crashes
|
||||
--> $DIR/explicit-paths-pass.rs:3:12
|
||||
|
|
||||
LL | #![feature(fn_delegation)]
|
||||
| ^^^^^^^^^^^^^
|
||||
|
|
||||
= note: see issue #118212 <https://github.com/rust-lang/rust/issues/118212> for more information
|
||||
= note: `#[warn(incomplete_features)]` on by default
|
||||
|
||||
warning: 1 warning emitted
|
||||
|
39
tests/ui/delegation/explicit-paths-signature-pass.rs
Normal file
39
tests/ui/delegation/explicit-paths-signature-pass.rs
Normal file
@ -0,0 +1,39 @@
|
||||
// run-pass
|
||||
|
||||
#![feature(fn_delegation)]
|
||||
//~^ WARN the feature `fn_delegation` is incomplete
|
||||
|
||||
mod to_reuse {
|
||||
use crate::S;
|
||||
|
||||
pub fn foo<'a>(#[cfg(FALSE)] a: u8, _b: &'a S) -> u32 {
|
||||
1
|
||||
}
|
||||
}
|
||||
|
||||
reuse to_reuse::foo;
|
||||
|
||||
trait Trait {
|
||||
fn foo(&self) -> u32 { 0 }
|
||||
fn bar(self: Box<Self>) -> u32 { 2 }
|
||||
fn baz(a: (i32, i32)) -> i32 { a.0 + a.1 }
|
||||
}
|
||||
|
||||
struct F;
|
||||
impl Trait for F {}
|
||||
|
||||
struct S(F);
|
||||
|
||||
impl Trait for S {
|
||||
reuse to_reuse::foo { self }
|
||||
reuse Trait::bar { Box::new(self.0) }
|
||||
reuse <F as Trait>::baz;
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let s = S(F);
|
||||
assert_eq!(1, foo(&s));
|
||||
assert_eq!(1, s.foo());
|
||||
assert_eq!(2, Box::new(s).bar());
|
||||
assert_eq!(4, S::baz((2, 2)));
|
||||
}
|
11
tests/ui/delegation/explicit-paths-signature-pass.stderr
Normal file
11
tests/ui/delegation/explicit-paths-signature-pass.stderr
Normal file
@ -0,0 +1,11 @@
|
||||
warning: the feature `fn_delegation` is incomplete and may not be safe to use and/or cause compiler crashes
|
||||
--> $DIR/explicit-paths-signature-pass.rs:3:12
|
||||
|
|
||||
LL | #![feature(fn_delegation)]
|
||||
| ^^^^^^^^^^^^^
|
||||
|
|
||||
= note: see issue #118212 <https://github.com/rust-lang/rust/issues/118212> for more information
|
||||
= note: `#[warn(incomplete_features)]` on by default
|
||||
|
||||
warning: 1 warning emitted
|
||||
|
25
tests/ui/delegation/explicit-paths.rs
Normal file
25
tests/ui/delegation/explicit-paths.rs
Normal file
@ -0,0 +1,25 @@
|
||||
#![feature(fn_delegation)]
|
||||
//~^ WARN the feature `fn_delegation` is incomplete
|
||||
|
||||
trait Trait {
|
||||
fn bar(&self) -> i32 { 42 }
|
||||
}
|
||||
|
||||
struct F;
|
||||
impl Trait for F {}
|
||||
|
||||
struct S(F);
|
||||
|
||||
impl Trait for S {
|
||||
reuse <F as Trait>::bar;
|
||||
//~^ ERROR mismatched types
|
||||
}
|
||||
|
||||
struct S2(F);
|
||||
|
||||
impl Trait for S2 {
|
||||
reuse <S2 as Trait>::bar { &self.0 }
|
||||
//~^ ERROR mismatched types
|
||||
}
|
||||
|
||||
fn main() {}
|
38
tests/ui/delegation/explicit-paths.stderr
Normal file
38
tests/ui/delegation/explicit-paths.stderr
Normal file
@ -0,0 +1,38 @@
|
||||
warning: the feature `fn_delegation` is incomplete and may not be safe to use and/or cause compiler crashes
|
||||
--> $DIR/explicit-paths.rs:1:12
|
||||
|
|
||||
LL | #![feature(fn_delegation)]
|
||||
| ^^^^^^^^^^^^^
|
||||
|
|
||||
= note: see issue #118212 <https://github.com/rust-lang/rust/issues/118212> for more information
|
||||
= note: `#[warn(incomplete_features)]` on by default
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/explicit-paths.rs:14:25
|
||||
|
|
||||
LL | reuse <F as Trait>::bar;
|
||||
| --------------^^^
|
||||
| | |
|
||||
| | expected `&F`, found `&S`
|
||||
| arguments to this function are incorrect
|
||||
|
|
||||
= note: expected reference `&F`
|
||||
found reference `&S`
|
||||
note: method defined here
|
||||
--> $DIR/explicit-paths.rs:5:8
|
||||
|
|
||||
LL | fn bar(&self) -> i32 { 42 }
|
||||
| ^^^ -----
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/explicit-paths.rs:21:32
|
||||
|
|
||||
LL | reuse <S2 as Trait>::bar { &self.0 }
|
||||
| ^^^^^^^ expected `&S2`, found `&F`
|
||||
|
|
||||
= note: expected reference `&S2`
|
||||
found reference `&F`
|
||||
|
||||
error: aborting due to 2 previous errors; 1 warning emitted
|
||||
|
||||
For more information about this error, try `rustc --explain E0308`.
|
111
tests/ui/delegation/not-supported.rs
Normal file
111
tests/ui/delegation/not-supported.rs
Normal file
@ -0,0 +1,111 @@
|
||||
#![feature(c_variadic)]
|
||||
#![feature(fn_delegation)]
|
||||
//~^ WARN the feature `fn_delegation` is incomplete
|
||||
|
||||
mod generics {
|
||||
trait GenericTrait<T> {
|
||||
fn bar(&self, x: T) -> T { x }
|
||||
fn bar1() {}
|
||||
}
|
||||
trait Trait {
|
||||
fn foo(&self, x: i32) -> i32 { x }
|
||||
fn foo1<'a>(&self, x: &'a i32) -> &'a i32 { x }
|
||||
fn foo2<T>(&self, x: T) -> T { x }
|
||||
fn foo3<'a: 'a>(_: &'a u32) {}
|
||||
|
||||
reuse GenericTrait::bar;
|
||||
//~^ delegation with early bound generics is not supported yet
|
||||
reuse GenericTrait::bar1;
|
||||
//~^ delegation with early bound generics is not supported yet
|
||||
}
|
||||
|
||||
struct F;
|
||||
impl Trait for F {}
|
||||
impl<T> GenericTrait<T> for F {}
|
||||
|
||||
struct S(F);
|
||||
|
||||
impl<T> GenericTrait<T> for S {
|
||||
reuse <F as GenericTrait<T>>::bar { &self.0 }
|
||||
//~^ ERROR delegation with early bound generics is not supported yet
|
||||
reuse GenericTrait::<T>::bar1;
|
||||
//~^ ERROR delegation with early bound generics is not supported yet
|
||||
}
|
||||
|
||||
impl GenericTrait<()> for () {
|
||||
reuse GenericTrait::bar { &F }
|
||||
//~^ ERROR delegation with early bound generics is not supported yet
|
||||
reuse GenericTrait::bar1;
|
||||
//~^ ERROR delegation with early bound generics is not supported yet
|
||||
}
|
||||
|
||||
impl Trait for &S {
|
||||
reuse Trait::foo;
|
||||
//~^ ERROR delegation with early bound generics is not supported yet
|
||||
}
|
||||
|
||||
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 method `foo2` has 0 type parameters but its trait declaration has 1 type parameter
|
||||
reuse <F as Trait>::foo3;
|
||||
//~^ ERROR delegation with early bound generics is not supported yet
|
||||
//~| ERROR lifetime parameters or bounds on method `foo3` do not match the trait declaration
|
||||
}
|
||||
|
||||
struct GenericS<T>(T);
|
||||
impl<T> Trait for GenericS<T> {
|
||||
reuse Trait::foo { &self.0 }
|
||||
//~^ ERROR delegation with early bound generics is not supported yet
|
||||
}
|
||||
}
|
||||
|
||||
mod opaque {
|
||||
trait Trait {}
|
||||
impl Trait for () {}
|
||||
|
||||
mod to_reuse {
|
||||
use super::Trait;
|
||||
|
||||
pub fn opaque_arg(_: impl Trait) -> i32 { 0 }
|
||||
pub fn opaque_ret() -> impl Trait { unimplemented!() }
|
||||
}
|
||||
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 {
|
||||
mod to_reuse {
|
||||
pub unsafe fn unsafe_fn() {}
|
||||
pub extern "C" fn extern_fn() {}
|
||||
pub unsafe extern "C" fn variadic_fn(n: usize, mut args: ...) {}
|
||||
pub const fn const_fn() {}
|
||||
}
|
||||
|
||||
reuse to_reuse::unsafe_fn;
|
||||
//~^ ERROR delegation to unsafe functions is not supported yet
|
||||
reuse to_reuse::extern_fn;
|
||||
//~^ ERROR delegation to non Rust ABI functions is not supported yet
|
||||
reuse to_reuse::variadic_fn;
|
||||
//~^ ERROR delegation to variadic functions is not supported yet
|
||||
reuse to_reuse::const_fn;
|
||||
//~^ 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() {}
|
184
tests/ui/delegation/not-supported.stderr
Normal file
184
tests/ui/delegation/not-supported.stderr
Normal file
@ -0,0 +1,184 @@
|
||||
warning: the feature `fn_delegation` is incomplete and may not be safe to use and/or cause compiler crashes
|
||||
--> $DIR/not-supported.rs:2:12
|
||||
|
|
||||
LL | #![feature(fn_delegation)]
|
||||
| ^^^^^^^^^^^^^
|
||||
|
|
||||
= note: see issue #118212 <https://github.com/rust-lang/rust/issues/118212> for more information
|
||||
= note: `#[warn(incomplete_features)]` on by default
|
||||
|
||||
error: delegation with early bound generics is not supported yet
|
||||
--> $DIR/not-supported.rs:16:29
|
||||
|
|
||||
LL | fn bar(&self, x: T) -> T { x }
|
||||
| ------------------------ callee defined here
|
||||
...
|
||||
LL | reuse GenericTrait::bar;
|
||||
| ^^^
|
||||
|
||||
error: delegation with early bound generics is not supported yet
|
||||
--> $DIR/not-supported.rs:18:29
|
||||
|
|
||||
LL | fn bar1() {}
|
||||
| --------- callee defined here
|
||||
...
|
||||
LL | reuse GenericTrait::bar1;
|
||||
| ^^^^
|
||||
|
||||
error: delegation with early bound generics is not supported yet
|
||||
--> $DIR/not-supported.rs:29:39
|
||||
|
|
||||
LL | fn bar(&self, x: T) -> T { x }
|
||||
| ------------------------ callee defined here
|
||||
...
|
||||
LL | reuse <F as GenericTrait<T>>::bar { &self.0 }
|
||||
| ^^^
|
||||
|
||||
error: delegation with early bound generics is not supported yet
|
||||
--> $DIR/not-supported.rs:31:34
|
||||
|
|
||||
LL | fn bar1() {}
|
||||
| --------- callee defined here
|
||||
...
|
||||
LL | reuse GenericTrait::<T>::bar1;
|
||||
| ^^^^
|
||||
|
||||
error: delegation with early bound generics is not supported yet
|
||||
--> $DIR/not-supported.rs:36:29
|
||||
|
|
||||
LL | fn bar(&self, x: T) -> T { x }
|
||||
| ------------------------ callee defined here
|
||||
...
|
||||
LL | reuse GenericTrait::bar { &F }
|
||||
| ^^^
|
||||
|
||||
error: delegation with early bound generics is not supported yet
|
||||
--> $DIR/not-supported.rs:38:29
|
||||
|
|
||||
LL | fn bar1() {}
|
||||
| --------- callee defined here
|
||||
...
|
||||
LL | reuse GenericTrait::bar1;
|
||||
| ^^^^
|
||||
|
||||
error: delegation with early bound generics is not supported yet
|
||||
--> $DIR/not-supported.rs:43:22
|
||||
|
|
||||
LL | fn foo(&self, x: i32) -> i32 { x }
|
||||
| ---------------------------- callee defined here
|
||||
...
|
||||
LL | reuse Trait::foo;
|
||||
| ^^^
|
||||
|
||||
error: delegation with early bound generics is not supported yet
|
||||
--> $DIR/not-supported.rs:49:22
|
||||
|
|
||||
LL | fn foo2<T>(&self, x: T) -> T { x }
|
||||
| ---------------------------- callee defined here
|
||||
...
|
||||
LL | reuse Trait::foo2 { &self.0 }
|
||||
| ^^^^
|
||||
|
||||
error: delegation with early bound generics is not supported yet
|
||||
--> $DIR/not-supported.rs:52:29
|
||||
|
|
||||
LL | fn foo3<'a: 'a>(_: &'a u32) {}
|
||||
| --------------------------- callee defined here
|
||||
...
|
||||
LL | reuse <F as Trait>::foo3;
|
||||
| ^^^^
|
||||
|
||||
error: delegation with early bound generics is not supported yet
|
||||
--> $DIR/not-supported.rs:59:22
|
||||
|
|
||||
LL | fn foo(&self, x: i32) -> i32 { x }
|
||||
| ---------------------------- callee defined here
|
||||
...
|
||||
LL | reuse Trait::foo { &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;
|
||||
| ^^^^^^^^^^
|
||||
|
||||
error: delegation to a function with opaque type is not supported yet
|
||||
--> $DIR/not-supported.rs:76:21
|
||||
|
|
||||
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:88:21
|
||||
|
|
||||
LL | pub unsafe fn unsafe_fn() {}
|
||||
| ------------------------- callee defined here
|
||||
...
|
||||
LL | reuse to_reuse::unsafe_fn;
|
||||
| ^^^^^^^^^
|
||||
|
||||
error: delegation to non Rust ABI functions is not supported yet
|
||||
--> $DIR/not-supported.rs:90:21
|
||||
|
|
||||
LL | pub extern "C" fn extern_fn() {}
|
||||
| ----------------------------- callee defined here
|
||||
...
|
||||
LL | reuse to_reuse::extern_fn;
|
||||
| ^^^^^^^^^
|
||||
|
||||
error: delegation to variadic functions is not supported yet
|
||||
--> $DIR/not-supported.rs:92:21
|
||||
|
|
||||
LL | pub unsafe extern "C" fn variadic_fn(n: usize, mut args: ...) {}
|
||||
| ------------------------------------------------------------- callee defined here
|
||||
...
|
||||
LL | reuse to_reuse::variadic_fn;
|
||||
| ^^^^^^^^^^^
|
||||
|
||||
error: delegation to const functions is not supported yet
|
||||
--> $DIR/not-supported.rs:94:21
|
||||
|
|
||||
LL | pub const fn const_fn() {}
|
||||
| ----------------------- callee defined here
|
||||
...
|
||||
LL | reuse to_reuse::const_fn;
|
||||
| ^^^^^^^^
|
||||
|
||||
error: recursive delegation is not supported yet
|
||||
--> $DIR/not-supported.rs:107:22
|
||||
|
|
||||
LL | pub reuse to_reuse2::foo;
|
||||
| --- callee defined here
|
||||
...
|
||||
LL | reuse to_reuse1::foo;
|
||||
| ^^^
|
||||
|
||||
error[E0049]: method `foo2` has 0 type parameters but its trait declaration has 1 type parameter
|
||||
--> $DIR/not-supported.rs:49:22
|
||||
|
|
||||
LL | fn foo2<T>(&self, x: T) -> T { x }
|
||||
| - expected 1 type parameter
|
||||
...
|
||||
LL | reuse Trait::foo2 { &self.0 }
|
||||
| ^^^^ found 0 type parameters
|
||||
|
||||
error[E0195]: lifetime parameters or bounds on method `foo3` do not match the trait declaration
|
||||
--> $DIR/not-supported.rs:52:29
|
||||
|
|
||||
LL | fn foo3<'a: 'a>(_: &'a u32) {}
|
||||
| -------- lifetimes in impl do not match this method in trait
|
||||
...
|
||||
LL | reuse <F as Trait>::foo3;
|
||||
| ^^^^ lifetimes do not match method in trait
|
||||
|
||||
error: aborting due to 19 previous errors; 1 warning emitted
|
||||
|
||||
Some errors have detailed explanations: E0049, E0195.
|
||||
For more information about an error, try `rustc --explain E0049`.
|
42
tests/ui/delegation/parse.rs
Normal file
42
tests/ui/delegation/parse.rs
Normal file
@ -0,0 +1,42 @@
|
||||
// check-pass
|
||||
|
||||
#![feature(decl_macro)]
|
||||
#![feature(fn_delegation)]
|
||||
//~^ WARN the feature `fn_delegation` is incomplete
|
||||
|
||||
macro_rules! reuse { {} => {} }
|
||||
|
||||
mod reuse {
|
||||
pub fn to_unsafe(x: i32) -> i32 { x + 1 }
|
||||
pub fn to_pub() {}
|
||||
pub fn to_pub2() {}
|
||||
|
||||
mod inner {
|
||||
#[allow(non_camel_case_types)]
|
||||
struct reuse {
|
||||
a: i32,
|
||||
b: i32,
|
||||
c: i32,
|
||||
}
|
||||
|
||||
impl reuse {
|
||||
reuse!();
|
||||
}
|
||||
|
||||
fn baz() {
|
||||
let (a, b, c) = (0, 0, 0);
|
||||
reuse {a, b, c};
|
||||
}
|
||||
}
|
||||
|
||||
pub macro my_macro() {}
|
||||
}
|
||||
|
||||
reuse!();
|
||||
reuse::my_macro!();
|
||||
|
||||
#[inline]
|
||||
pub reuse reuse::to_pub;
|
||||
pub reuse crate::reuse::to_pub2;
|
||||
|
||||
fn main() {}
|
11
tests/ui/delegation/parse.stderr
Normal file
11
tests/ui/delegation/parse.stderr
Normal file
@ -0,0 +1,11 @@
|
||||
warning: the feature `fn_delegation` is incomplete and may not be safe to use and/or cause compiler crashes
|
||||
--> $DIR/parse.rs:4:12
|
||||
|
|
||||
LL | #![feature(fn_delegation)]
|
||||
| ^^^^^^^^^^^^^
|
||||
|
|
||||
= note: see issue #118212 <https://github.com/rust-lang/rust/issues/118212> for more information
|
||||
= note: `#[warn(incomplete_features)]` on by default
|
||||
|
||||
warning: 1 warning emitted
|
||||
|
37
tests/ui/delegation/target-expr-pass.rs
Normal file
37
tests/ui/delegation/target-expr-pass.rs
Normal file
@ -0,0 +1,37 @@
|
||||
// run-pass
|
||||
|
||||
#![feature(fn_delegation)]
|
||||
//~^ WARN the feature `fn_delegation` is incomplete
|
||||
|
||||
mod to_reuse {
|
||||
pub fn foo(x: i32) -> i32 { x }
|
||||
pub mod inner {}
|
||||
}
|
||||
|
||||
reuse to_reuse::foo {{
|
||||
use self::to_reuse::foo;
|
||||
let x = foo(12);
|
||||
x + self
|
||||
}}
|
||||
|
||||
trait Trait {
|
||||
fn bar(&self, x: i32) -> i32 { x }
|
||||
}
|
||||
|
||||
struct F;
|
||||
impl Trait for F {}
|
||||
|
||||
struct S(F);
|
||||
impl Trait for S {
|
||||
reuse <F as Trait>::bar {
|
||||
#[allow(unused_imports)]
|
||||
use self::to_reuse::{foo, inner::self};
|
||||
let x = foo(12);
|
||||
assert_eq!(x, 12);
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
assert_eq!(foo(12), 24);
|
||||
}
|
11
tests/ui/delegation/target-expr-pass.stderr
Normal file
11
tests/ui/delegation/target-expr-pass.stderr
Normal file
@ -0,0 +1,11 @@
|
||||
warning: the feature `fn_delegation` is incomplete and may not be safe to use and/or cause compiler crashes
|
||||
--> $DIR/target-expr-pass.rs:3:12
|
||||
|
|
||||
LL | #![feature(fn_delegation)]
|
||||
| ^^^^^^^^^^^^^
|
||||
|
|
||||
= note: see issue #118212 <https://github.com/rust-lang/rust/issues/118212> for more information
|
||||
= note: `#[warn(incomplete_features)]` on by default
|
||||
|
||||
warning: 1 warning emitted
|
||||
|
@ -1,3 +1,8 @@
|
||||
todo!(); //~ ERROR
|
||||
mod to_reuse {
|
||||
pub fn foo() {}
|
||||
}
|
||||
|
||||
reuse to_reuse::foo;
|
||||
//~^ ERROR functions delegation is not yet fully implemented
|
||||
|
||||
fn main() {}
|
||||
|
@ -1,13 +1,12 @@
|
||||
error: expected one of `!` or `::`, found `(`
|
||||
--> $DIR/feature-gate-fn_delegation.rs:1:1
|
||||
error[E0658]: functions delegation is not yet fully implemented
|
||||
--> $DIR/feature-gate-fn_delegation.rs:5:1
|
||||
|
|
||||
LL | todo!();
|
||||
| ^^^^^^^
|
||||
| |
|
||||
| expected one of `!` or `::`
|
||||
| in this macro invocation
|
||||
LL | reuse to_reuse::foo;
|
||||
| ^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: this error originates in the macro `todo` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
= note: see issue #118212 <https://github.com/rust-lang/rust/issues/118212> for more information
|
||||
= help: add `#![feature(fn_delegation)]` to the crate attributes to enable
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0658`.
|
||||
|
Loading…
Reference in New Issue
Block a user