diff --git a/Cargo.lock b/Cargo.lock
index 75c7de4f405aa..78f3e22f95b3e 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -119,6 +119,16 @@ dependencies = [
"yansi-term",
]
+[[package]]
+name = "annotate-snippets"
+version = "0.10.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0a433302f833baa830c0092100c481c7ea768c5981a3c36f549517a502f246dd"
+dependencies = [
+ "anstyle",
+ "unicode-width",
+]
+
[[package]]
name = "ansi_term"
version = "0.12.1"
@@ -3771,7 +3781,7 @@ dependencies = [
name = "rustc_errors"
version = "0.0.0"
dependencies = [
- "annotate-snippets",
+ "annotate-snippets 0.10.1",
"derive_setters",
"rustc_ast",
"rustc_ast_pretty",
@@ -3831,7 +3841,7 @@ dependencies = [
name = "rustc_fluent_macro"
version = "0.0.0"
dependencies = [
- "annotate-snippets",
+ "annotate-snippets 0.10.1",
"fluent-bundle",
"fluent-syntax",
"proc-macro2",
@@ -4738,7 +4748,7 @@ dependencies = [
name = "rustfmt-nightly"
version = "1.7.0"
dependencies = [
- "annotate-snippets",
+ "annotate-snippets 0.9.1",
"anyhow",
"bytecount",
"cargo_metadata 0.15.4",
@@ -5728,7 +5738,7 @@ version = "0.21.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "aaf4bf7c184b8dfc7a4d3b90df789b1eb992ee42811cd115f32a7a1eb781058d"
dependencies = [
- "annotate-snippets",
+ "annotate-snippets 0.9.1",
"anyhow",
"bstr",
"cargo-platform",
@@ -5859,9 +5869,9 @@ checksum = "1dd624098567895118886609431a7c3b8f516e41d30e0643f03d94592a147e36"
[[package]]
name = "unicode-width"
-version = "0.1.10"
+version = "0.1.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b"
+checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85"
dependencies = [
"compiler_builtins",
"rustc-std-workspace-core",
diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs
index e1e4e5fc56750..21077c312bdc8 100644
--- a/compiler/rustc_ast/src/ast.rs
+++ b/compiler/rustc_ast/src/ast.rs
@@ -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
>,
}
+#[derive(Clone, Encodable, Decodable, Debug)]
+pub struct Delegation {
+ /// Path resolution id.
+ pub id: NodeId,
+ pub qself: Option
>,
+ pub path: Path,
+ pub body: Option
>,
+}
+
#[derive(Clone, Encodable, Decodable, Debug)]
pub struct StaticItem {
pub ty: P,
@@ -3104,6 +3114,11 @@ pub enum ItemKind {
/// A macro definition.
MacroDef(MacroDef),
+
+ /// A delegation item (`reuse`).
+ ///
+ /// E.g. `reuse ::name { target_expr_template }`.
+ Delegation(Box),
}
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),
/// A macro expanding to associated items.
MacCall(P),
+ /// An associated delegation item.
+ Delegation(Box),
}
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 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 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),
})
}
diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs
index 82f28143630d3..450555d0cb56d 100644
--- a/compiler/rustc_ast/src/mut_visit.rs
+++ b/compiler/rustc_ast/src/mut_visit.rs
@@ -1117,6 +1117,14 @@ pub fn noop_visit_item_kind(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(
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);
diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs
index 45261ca48fc25..3617df931e2a2 100644
--- a/compiler/rustc_ast/src/visit.rs
+++ b/compiler/rustc_ast/src/visit.rs
@@ -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);
+ }
+ }
}
}
diff --git a/compiler/rustc_ast_lowering/src/delegation.rs b/compiler/rustc_ast_lowering/src/delegation.rs
new file mode 100644
index 0000000000000..6ccf39b0cb167
--- /dev/null
+++ b/compiler/rustc_ast_lowering/src/delegation.rs
@@ -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 ::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. `::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 {
+ 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> = Vec::new();
+ let mut args: Vec> = 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);
+ }
+}
diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs
index d8de447e5b4cd..a3ff02f5f6954 100644
--- a/compiler/rustc_ast_lowering/src/item.rs
+++ b/compiler/rustc_ast_lowering/src/item.rs
@@ -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,
}
}
diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs
index dc23b1dce7bf5..d2d42a15808ba 100644
--- a/compiler/rustc_ast_lowering/src/lib.rs
+++ b/compiler/rustc_ast_lowering/src/lib.rs
@@ -77,6 +77,7 @@ macro_rules! arena_vec {
mod asm;
mod block;
+mod delegation;
mod errors;
mod expr;
mod format;
diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs
index 737e81eb6ecc0..539b520f54f4e 100644
--- a/compiler/rustc_ast_passes/src/feature_gate.rs
+++ b/compiler/rustc_ast_passes/src/feature_gate.rs
@@ -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) {
diff --git a/compiler/rustc_ast_pretty/src/pprust/state/item.rs b/compiler/rustc_ast_pretty/src/pprust/state/item.rs
index 43561a1c0209c..584f01e16c2c3 100644
--- a/compiler/rustc_ast_pretty/src/pprust/state/item.rs
+++ b/compiler/rustc_ast_pretty/src/pprust/state/item.rs
@@ -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,
diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs
index 495b255583c2a..0457b4e6ddc78 100644
--- a/compiler/rustc_borrowck/src/lib.rs
+++ b/compiler/rustc_borrowck/src/lib.rs
@@ -2399,10 +2399,10 @@ mod error {
/// and we want only the best of those errors.
///
/// The `report_use_of_moved_or_uninitialized` function checks this map and replaces the
- /// diagnostic (if there is one) if the `Place` of the error being reported is a prefix of the
- /// `Place` of the previous most diagnostic. This happens instead of buffering the error. Once
- /// all move errors have been reported, any diagnostics in this map are added to the buffer
- /// to be emitted.
+ /// diagnostic (if there is one) if the `Place` of the error being reported is a prefix of
+ /// the `Place` of the previous most diagnostic. This happens instead of buffering the
+ /// error. Once all move errors have been reported, any diagnostics in this map are added
+ /// to the buffer to be emitted.
///
/// `BTreeMap` is used to preserve the order of insertions when iterating. This is necessary
/// when errors in the map are being re-added to the error buffer so that errors with the
@@ -2410,7 +2410,8 @@ mod error {
buffered_move_errors:
BTreeMap, (PlaceRef<'tcx>, DiagnosticBuilder<'tcx>)>,
buffered_mut_errors: FxIndexMap, usize)>,
- /// Diagnostics to be reported buffer.
+ /// Buffer of diagnostics to be reported. Uses `Diagnostic` rather than `DiagnosticBuilder`
+ /// because it has a mixture of error diagnostics and non-error diagnostics.
buffered: Vec,
/// Set to Some if we emit an error during borrowck
tainted_by_errors: Option,
@@ -2434,11 +2435,11 @@ mod error {
"diagnostic buffered but not emitted",
))
}
- t.buffer(&mut self.buffered);
+ self.buffered.push(t.into_diagnostic());
}
pub fn buffer_non_error_diag(&mut self, t: DiagnosticBuilder<'_, ()>) {
- t.buffer(&mut self.buffered);
+ self.buffered.push(t.into_diagnostic());
}
pub fn set_tainted_by_errors(&mut self, e: ErrorGuaranteed) {
@@ -2486,13 +2487,13 @@ mod error {
// Buffer any move errors that we collected and de-duplicated.
for (_, (_, diag)) in std::mem::take(&mut self.errors.buffered_move_errors) {
// We have already set tainted for this error, so just buffer it.
- diag.buffer(&mut self.errors.buffered);
+ self.errors.buffered.push(diag.into_diagnostic());
}
for (_, (mut diag, count)) in std::mem::take(&mut self.errors.buffered_mut_errors) {
if count > 10 {
diag.note(format!("...and {} other attempted mutable borrows", count - 10));
}
- diag.buffer(&mut self.errors.buffered);
+ self.errors.buffered.push(diag.into_diagnostic());
}
if !self.errors.buffered.is_empty() {
diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/ffi.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/ffi.rs
index 7ad2d03a5edd5..017843c7e7d15 100644
--- a/compiler/rustc_codegen_llvm/src/coverageinfo/ffi.rs
+++ b/compiler/rustc_codegen_llvm/src/coverageinfo/ffi.rs
@@ -1,4 +1,4 @@
-use rustc_middle::mir::coverage::{CounterId, CovTerm, ExpressionId};
+use rustc_middle::mir::coverage::{CodeRegion, CounterId, CovTerm, ExpressionId, MappingKind};
/// Must match the layout of `LLVMRustCounterKind`.
#[derive(Copy, Clone, Debug)]
@@ -149,6 +149,24 @@ pub struct CounterMappingRegion {
}
impl CounterMappingRegion {
+ pub(crate) fn from_mapping(
+ mapping_kind: &MappingKind,
+ local_file_id: u32,
+ code_region: &CodeRegion,
+ ) -> Self {
+ let &CodeRegion { file_name: _, start_line, start_col, end_line, end_col } = code_region;
+ match *mapping_kind {
+ MappingKind::Code(term) => Self::code_region(
+ Counter::from_term(term),
+ local_file_id,
+ start_line,
+ start_col,
+ end_line,
+ end_col,
+ ),
+ }
+ }
+
pub(crate) fn code_region(
counter: Counter,
file_id: u32,
diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/map_data.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/map_data.rs
index cd67fafb8e4e2..d85d9411f03b6 100644
--- a/compiler/rustc_codegen_llvm/src/coverageinfo/map_data.rs
+++ b/compiler/rustc_codegen_llvm/src/coverageinfo/map_data.rs
@@ -4,7 +4,8 @@ use rustc_data_structures::captures::Captures;
use rustc_data_structures::fx::FxIndexSet;
use rustc_index::bit_set::BitSet;
use rustc_middle::mir::coverage::{
- CodeRegion, CounterId, CovTerm, Expression, ExpressionId, FunctionCoverageInfo, Mapping, Op,
+ CodeRegion, CounterId, CovTerm, Expression, ExpressionId, FunctionCoverageInfo, Mapping,
+ MappingKind, Op,
};
use rustc_middle::ty::Instance;
use rustc_span::Symbol;
@@ -64,8 +65,8 @@ impl<'tcx> FunctionCoverageCollector<'tcx> {
// For each expression ID that is directly used by one or more mappings,
// mark it as not-yet-seen. This indicates that we expect to see a
// corresponding `ExpressionUsed` statement during MIR traversal.
- for Mapping { term, .. } in &function_coverage_info.mappings {
- if let &CovTerm::Expression(id) = term {
+ for term in function_coverage_info.mappings.iter().flat_map(|m| m.kind.terms()) {
+ if let CovTerm::Expression(id) = term {
expressions_seen.remove(id);
}
}
@@ -221,20 +222,21 @@ impl<'tcx> FunctionCoverage<'tcx> {
/// that will be used by `mapgen` when preparing for FFI.
pub(crate) fn counter_regions(
&self,
- ) -> impl Iterator- + ExactSizeIterator {
+ ) -> impl Iterator
- + ExactSizeIterator {
self.function_coverage_info.mappings.iter().map(move |mapping| {
- let &Mapping { term, ref code_region } = mapping;
- let counter = self.counter_for_term(term);
- (counter, code_region)
+ let Mapping { kind, code_region } = mapping;
+ let kind =
+ kind.map_terms(|term| if self.is_zero_term(term) { CovTerm::Zero } else { term });
+ (kind, code_region)
})
}
fn counter_for_term(&self, term: CovTerm) -> Counter {
- if is_zero_term(&self.counters_seen, &self.zero_expressions, term) {
- Counter::ZERO
- } else {
- Counter::from_term(term)
- }
+ if self.is_zero_term(term) { Counter::ZERO } else { Counter::from_term(term) }
+ }
+
+ fn is_zero_term(&self, term: CovTerm) -> bool {
+ is_zero_term(&self.counters_seen, &self.zero_expressions, term)
}
}
diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs
index 51df14df644e0..6116a6fd222b3 100644
--- a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs
+++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs
@@ -12,7 +12,6 @@ use rustc_hir::def_id::DefId;
use rustc_index::IndexVec;
use rustc_middle::bug;
use rustc_middle::mir;
-use rustc_middle::mir::coverage::CodeRegion;
use rustc_middle::ty::{self, TyCtxt};
use rustc_span::def_id::DefIdSet;
use rustc_span::Symbol;
@@ -237,7 +236,7 @@ fn encode_mappings_for_function(
// Prepare file IDs for each filename, and prepare the mapping data so that
// we can pass it through FFI to LLVM.
for (file_name, counter_regions_for_file) in
- &counter_regions.group_by(|(_counter, region)| region.file_name)
+ &counter_regions.group_by(|(_, region)| region.file_name)
{
// Look up the global file ID for this filename.
let global_file_id = global_file_table.global_file_id_for_file_name(file_name);
@@ -248,17 +247,12 @@ fn encode_mappings_for_function(
// For each counter/region pair in this function+file, convert it to a
// form suitable for FFI.
- for (counter, region) in counter_regions_for_file {
- let CodeRegion { file_name: _, start_line, start_col, end_line, end_col } = *region;
-
- debug!("Adding counter {counter:?} to map for {region:?}");
- mapping_regions.push(CounterMappingRegion::code_region(
- counter,
+ for (mapping_kind, region) in counter_regions_for_file {
+ debug!("Adding counter {mapping_kind:?} to map for {region:?}");
+ mapping_regions.push(CounterMappingRegion::from_mapping(
+ &mapping_kind,
local_file_id.as_u32(),
- start_line,
- start_col,
- end_line,
- end_col,
+ region,
));
}
}
diff --git a/compiler/rustc_const_eval/src/transform/check_consts/check.rs b/compiler/rustc_const_eval/src/transform/check_consts/check.rs
index 738c532964a2c..ae9595d7e6444 100644
--- a/compiler/rustc_const_eval/src/transform/check_consts/check.rs
+++ b/compiler/rustc_const_eval/src/transform/check_consts/check.rs
@@ -1,6 +1,6 @@
//! The `Visitor` responsible for actually checking a `mir::Body` for invalid operations.
-use rustc_errors::{Diagnostic, ErrorGuaranteed};
+use rustc_errors::{DiagnosticBuilder, ErrorGuaranteed};
use rustc_hir as hir;
use rustc_hir::def_id::DefId;
use rustc_index::bit_set::BitSet;
@@ -214,7 +214,7 @@ pub struct Checker<'mir, 'tcx> {
local_has_storage_dead: Option>,
error_emitted: Option,
- secondary_errors: Vec,
+ secondary_errors: Vec>,
}
impl<'mir, 'tcx> Deref for Checker<'mir, 'tcx> {
@@ -272,14 +272,17 @@ impl<'mir, 'tcx> Checker<'mir, 'tcx> {
}
// If we got through const-checking without emitting any "primary" errors, emit any
- // "secondary" errors if they occurred.
+ // "secondary" errors if they occurred. Otherwise, cancel the "secondary" errors.
let secondary_errors = mem::take(&mut self.secondary_errors);
if self.error_emitted.is_none() {
for error in secondary_errors {
- self.tcx.dcx().emit_diagnostic(error);
+ error.emit();
}
} else {
assert!(self.tcx.dcx().has_errors().is_some());
+ for error in secondary_errors {
+ error.cancel();
+ }
}
}
@@ -347,7 +350,7 @@ impl<'mir, 'tcx> Checker<'mir, 'tcx> {
self.error_emitted = Some(reported);
}
- ops::DiagnosticImportance::Secondary => err.buffer(&mut self.secondary_errors),
+ ops::DiagnosticImportance::Secondary => self.secondary_errors.push(err),
}
}
diff --git a/compiler/rustc_errors/Cargo.toml b/compiler/rustc_errors/Cargo.toml
index fc3ff835a8136..0c1fcecb57173 100644
--- a/compiler/rustc_errors/Cargo.toml
+++ b/compiler/rustc_errors/Cargo.toml
@@ -5,7 +5,7 @@ edition = "2021"
[dependencies]
# tidy-alphabetical-start
-annotate-snippets = "0.9"
+annotate-snippets = "0.10"
derive_setters = "0.1.6"
rustc_ast = { path = "../rustc_ast" }
rustc_ast_pretty = { path = "../rustc_ast_pretty" }
diff --git a/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs b/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs
index 97f2efa7874d1..980ac31011931 100644
--- a/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs
+++ b/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs
@@ -12,8 +12,7 @@ use crate::{
CodeSuggestion, Diagnostic, DiagnosticId, DiagnosticMessage, Emitter, FluentBundle,
LazyFallbackBundle, Level, MultiSpan, Style, SubDiagnostic,
};
-use annotate_snippets::display_list::{DisplayList, FormatOptions};
-use annotate_snippets::snippet::*;
+use annotate_snippets::{Annotation, AnnotationType, Renderer, Slice, Snippet, SourceAnnotation};
use rustc_data_structures::sync::Lrc;
use rustc_error_messages::FluentArgs;
use rustc_span::source_map::SourceMap;
@@ -190,11 +189,6 @@ impl AnnotateSnippetEmitter {
annotation_type: annotation_type_for_level(*level),
}),
footer: vec![],
- opt: FormatOptions {
- color: true,
- anonymized_line_numbers: self.ui_testing,
- margin: None,
- },
slices: annotated_files
.iter()
.map(|(file_name, source, line_index, annotations)| {
@@ -222,7 +216,8 @@ impl AnnotateSnippetEmitter {
// FIXME(#59346): Figure out if we can _always_ print to stderr or not.
// `emitter.rs` has the `Destination` enum that lists various possible output
// destinations.
- eprintln!("{}", DisplayList::from(snippet))
+ let renderer = Renderer::plain().anonymized_line_numbers(self.ui_testing);
+ eprintln!("{}", renderer.render(snippet))
}
// FIXME(#59346): Is it ok to return None if there's no source_map?
}
diff --git a/compiler/rustc_errors/src/diagnostic_builder.rs b/compiler/rustc_errors/src/diagnostic_builder.rs
index a02909f29c45d..bd7c58d904e70 100644
--- a/compiler/rustc_errors/src/diagnostic_builder.rs
+++ b/compiler/rustc_errors/src/diagnostic_builder.rs
@@ -255,35 +255,13 @@ impl<'a, G: EmissionGuarantee> DiagnosticBuilder<'a, G> {
/// Stashes diagnostic for possible later improvement in a different,
/// later stage of the compiler. The diagnostic can be accessed with
/// the provided `span` and `key` through [`DiagCtxt::steal_diagnostic()`].
- ///
- /// As with `buffer`, this is unless the dcx has disabled such buffering.
pub fn stash(self, span: Span, key: StashKey) {
- if let Some((diag, dcx)) = self.into_diagnostic() {
- dcx.stash_diagnostic(span, key, diag);
- }
- }
-
- /// Converts the builder to a `Diagnostic` for later emission,
- /// unless dcx has disabled such buffering.
- fn into_diagnostic(mut self) -> Option<(Diagnostic, &'a DiagCtxt)> {
- if self.dcx.inner.lock().flags.treat_err_as_bug.is_some() {
- self.emit();
- return None;
- }
-
- let diag = self.take_diag();
-
- // Logging here is useful to help track down where in logs an error was
- // actually emitted.
- debug!("buffer: diag={:?}", diag);
-
- Some((diag, self.dcx))
+ self.dcx.stash_diagnostic(span, key, self.into_diagnostic());
}
- /// Buffers the diagnostic for later emission,
- /// unless dcx has disabled such buffering.
- pub fn buffer(self, buffered_diagnostics: &mut Vec) {
- buffered_diagnostics.extend(self.into_diagnostic().map(|(diag, _)| diag));
+ /// Converts the builder to a `Diagnostic` for later emission.
+ pub fn into_diagnostic(mut self) -> Diagnostic {
+ self.take_diag()
}
/// Delay emission of this diagnostic as a bug.
diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs
index 8fb539fc3582f..404c89ea01b64 100644
--- a/compiler/rustc_errors/src/lib.rs
+++ b/compiler/rustc_errors/src/lib.rs
@@ -981,6 +981,10 @@ impl DiagCtxt {
inner.emit_stashed_diagnostics();
+ if inner.treat_err_as_bug() {
+ return;
+ }
+
let warnings = match inner.deduplicated_warn_count {
0 => Cow::from(""),
1 => Cow::from("1 warning emitted"),
@@ -991,9 +995,6 @@ impl DiagCtxt {
1 => Cow::from("aborting due to 1 previous error"),
count => Cow::from(format!("aborting due to {count} previous errors")),
};
- if inner.treat_err_as_bug() {
- return;
- }
match (errors.len(), warnings.len()) {
(0, 0) => return,
@@ -1168,7 +1169,8 @@ impl DiagCtxt {
let mut inner = self.inner.borrow_mut();
if loud && lint_level.is_error() {
- inner.bump_err_count();
+ inner.err_count += 1;
+ inner.panic_if_treat_err_as_bug();
}
inner.emitter.emit_unused_externs(lint_level, unused_externs)
@@ -1255,7 +1257,7 @@ impl DiagCtxtInner {
}
fn emit_diagnostic(&mut self, mut diagnostic: Diagnostic) -> Option {
- if matches!(diagnostic.level, Error | Fatal) && self.treat_err_as_bug() {
+ if matches!(diagnostic.level, Error | Fatal) && self.treat_next_err_as_bug() {
diagnostic.level = Bug;
}
@@ -1353,10 +1355,11 @@ impl DiagCtxtInner {
}
if diagnostic.is_error() {
if diagnostic.is_lint {
- self.bump_lint_err_count();
+ self.lint_err_count += 1;
} else {
- self.bump_err_count();
+ self.err_count += 1;
}
+ self.panic_if_treat_err_as_bug();
#[allow(deprecated)]
{
@@ -1447,16 +1450,6 @@ impl DiagCtxtInner {
panic::panic_any(DelayedBugPanic);
}
- fn bump_lint_err_count(&mut self) {
- self.lint_err_count += 1;
- self.panic_if_treat_err_as_bug();
- }
-
- fn bump_err_count(&mut self) {
- self.err_count += 1;
- self.panic_if_treat_err_as_bug();
- }
-
fn panic_if_treat_err_as_bug(&self) {
if self.treat_err_as_bug() {
match (
diff --git a/compiler/rustc_errors/src/markdown/tests/term.rs b/compiler/rustc_errors/src/markdown/tests/term.rs
index a0d956bf0cdab..bab47dcc175f1 100644
--- a/compiler/rustc_errors/src/markdown/tests/term.rs
+++ b/compiler/rustc_errors/src/markdown/tests/term.rs
@@ -5,7 +5,8 @@ use termcolor::{BufferWriter, ColorChoice};
use super::*;
const INPUT: &str = include_str!("input.md");
-const OUTPUT_PATH: &[&str] = &[env!("CARGO_MANIFEST_DIR"), "src","markdown","tests","output.stdout"];
+const OUTPUT_PATH: &[&str] =
+ &[env!("CARGO_MANIFEST_DIR"), "src", "markdown", "tests", "output.stdout"];
const TEST_WIDTH: usize = 80;
@@ -34,7 +35,7 @@ quis dolor non venenatis. Aliquam ut. ";
fn test_wrapping_write() {
WIDTH.with(|w| w.set(TEST_WIDTH));
let mut buf = BufWriter::new(Vec::new());
- let txt = TXT.replace("-\n","-").replace("_\n","_").replace('\n', " ").replace(" ", "");
+ let txt = TXT.replace("-\n", "-").replace("_\n", "_").replace('\n', " ").replace(" ", "");
write_wrapping(&mut buf, &txt, 0, None).unwrap();
write_wrapping(&mut buf, &txt, 4, None).unwrap();
write_wrapping(
diff --git a/compiler/rustc_fluent_macro/Cargo.toml b/compiler/rustc_fluent_macro/Cargo.toml
index 872dd29a7a8ac..c5a53ae831355 100644
--- a/compiler/rustc_fluent_macro/Cargo.toml
+++ b/compiler/rustc_fluent_macro/Cargo.toml
@@ -8,7 +8,7 @@ proc-macro = true
[dependencies]
# tidy-alphabetical-start
-annotate-snippets = "0.9"
+annotate-snippets = "0.10"
fluent-bundle = "0.15.2"
fluent-syntax = "0.11"
proc-macro2 = "1"
diff --git a/compiler/rustc_fluent_macro/src/fluent.rs b/compiler/rustc_fluent_macro/src/fluent.rs
index 3b1b63455eddd..520a64aaf5e23 100644
--- a/compiler/rustc_fluent_macro/src/fluent.rs
+++ b/compiler/rustc_fluent_macro/src/fluent.rs
@@ -1,7 +1,4 @@
-use annotate_snippets::{
- display_list::DisplayList,
- snippet::{Annotation, AnnotationType, Slice, Snippet, SourceAnnotation},
-};
+use annotate_snippets::{Annotation, AnnotationType, Renderer, Slice, Snippet, SourceAnnotation};
use fluent_bundle::{FluentBundle, FluentError, FluentResource};
use fluent_syntax::{
ast::{
@@ -179,10 +176,9 @@ pub(crate) fn fluent_messages(input: proc_macro::TokenStream) -> proc_macro::Tok
range: (pos.start, pos.end - 1),
}],
}],
- opt: Default::default(),
};
- let dl = DisplayList::from(snippet);
- eprintln!("{dl}\n");
+ let renderer = Renderer::plain();
+ eprintln!("{}\n", renderer.render(snippet));
}
return failed(&crate_name);
diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs
index 58ac9668da5e9..6b347f7035a3b 100644
--- a/compiler/rustc_hir/src/hir.rs
+++ b/compiler/rustc_hir/src/hir.rs
@@ -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]`).
diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs
index dd3633b6b4f74..adc090258093a 100644
--- a/compiler/rustc_hir/src/intravisit.rs
+++ b/compiler/rustc_hir/src/intravisit.rs
@@ -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(_) => {}
}
}
diff --git a/compiler/rustc_hir_analysis/messages.ftl b/compiler/rustc_hir_analysis/messages.ftl
index 6a17668ad17f8..432c9c12cbfbc 100644
--- a/compiler/rustc_hir_analysis/messages.ftl
+++ b/compiler/rustc_hir_analysis/messages.ftl
@@ -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
diff --git a/compiler/rustc_hir_analysis/src/astconv/bounds.rs b/compiler/rustc_hir_analysis/src/astconv/bounds.rs
index 1f88aaa6a4b01..2ad96a2489124 100644
--- a/compiler/rustc_hir_analysis/src/astconv/bounds.rs
+++ b/compiler/rustc_hir_analysis/src/astconv/bounds.rs
@@ -300,13 +300,15 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
.expect("missing associated item");
if !assoc_item.visibility(tcx).is_accessible_from(def_scope, tcx) {
- tcx.dcx()
+ let reported = tcx
+ .dcx()
.struct_span_err(
binding.span,
format!("{} `{}` is private", assoc_item.kind, binding.item_name),
)
.with_span_label(binding.span, format!("private {}", assoc_item.kind))
.emit();
+ self.set_tainted_by_errors(reported);
}
tcx.check_stability(assoc_item.def_id, Some(hir_ref_id), binding.span, None);
diff --git a/compiler/rustc_hir_analysis/src/astconv/errors.rs b/compiler/rustc_hir_analysis/src/astconv/errors.rs
index fc2ed104b3dc8..7b23b74f82920 100644
--- a/compiler/rustc_hir_analysis/src/astconv/errors.rs
+++ b/compiler/rustc_hir_analysis/src/astconv/errors.rs
@@ -354,7 +354,9 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
);
err.span_label(name.span, format!("multiple `{name}` found"));
self.note_ambiguous_inherent_assoc_type(&mut err, candidates, span);
- err.emit()
+ let reported = err.emit();
+ self.set_tainted_by_errors(reported);
+ reported
}
// FIXME(fmease): Heavily adapted from `rustc_hir_typeck::method::suggest`. Deduplicate.
@@ -843,7 +845,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
}
}
- err.emit();
+ self.set_tainted_by_errors(err.emit());
}
}
diff --git a/compiler/rustc_hir_analysis/src/astconv/mod.rs b/compiler/rustc_hir_analysis/src/astconv/mod.rs
index 1f47564649eda..78740ac33ca09 100644
--- a/compiler/rustc_hir_analysis/src/astconv/mod.rs
+++ b/compiler/rustc_hir_analysis/src/astconv/mod.rs
@@ -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;
@@ -390,6 +389,12 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
infer_args,
);
+ if let Err(err) = &arg_count.correct
+ && let Some(reported) = err.reported
+ {
+ self.set_tainted_by_errors(reported);
+ }
+
// Skip processing if type has no generic parameters.
// Traits always have `Self` as a generic parameter, which means they will not return early
// here and so associated type bindings will be handled regardless of whether there are any
@@ -568,6 +573,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
span,
modifier: constness.as_str(),
});
+ self.set_tainted_by_errors(e);
arg_count.correct =
Err(GenericArgCountMismatch { reported: Some(e), invalid_args: vec![] });
}
@@ -966,7 +972,9 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
}
}
}
- err.emit()
+ let reported = err.emit();
+ self.set_tainted_by_errors(reported);
+ reported
}
// Search for a bound on a type parameter which includes the associated item
@@ -1043,6 +1051,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
span,
binding,
);
+ self.set_tainted_by_errors(reported);
return Err(reported);
};
debug!(?bound);
@@ -1120,6 +1129,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
));
}
let reported = err.emit();
+ self.set_tainted_by_errors(reported);
if !where_bounds.is_empty() {
return Err(reported);
}
@@ -1374,6 +1384,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
assoc_ident.name,
)
};
+ self.set_tainted_by_errors(reported);
return Err(reported);
}
};
@@ -1616,12 +1627,14 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
let kind = tcx.def_kind_descr(kind, item);
let msg = format!("{kind} `{name}` is private");
let def_span = tcx.def_span(item);
- tcx.dcx()
+ let reported = tcx
+ .dcx()
.struct_span_err(span, msg)
.with_code(rustc_errors::error_code!(E0624))
.with_span_label(span, format!("private {kind}"))
.with_span_label(def_span, format!("{kind} defined here"))
.emit();
+ self.set_tainted_by_errors(reported);
}
tcx.check_stability(item, Some(block), span, None);
}
@@ -1862,7 +1875,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
err.span_label(span, format!("not allowed on {what}"));
}
extend(&mut err);
- err.emit();
+ self.set_tainted_by_errors(err.emit());
emitted = true;
}
@@ -2184,7 +2197,9 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
{
err.span_note(impl_.self_ty.span, "not a concrete type");
}
- Ty::new_error(tcx, err.emit())
+ let reported = err.emit();
+ self.set_tainted_by_errors(reported);
+ Ty::new_error(tcx, reported)
} else {
ty
}
@@ -2306,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)]
@@ -2313,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 })
@@ -2504,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.
@@ -2586,7 +2718,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
);
}
- diag.emit();
+ self.set_tainted_by_errors(diag.emit());
}
// Find any late-bound regions declared in return type that do
@@ -2686,7 +2818,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
err.note("consider introducing a named lifetime parameter");
}
- err.emit();
+ self.set_tainted_by_errors(err.emit());
}
}
@@ -2725,7 +2857,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
// error.
let r = derived_region_bounds[0];
if derived_region_bounds[1..].iter().any(|r1| r != *r1) {
- tcx.dcx().emit_err(AmbiguousLifetimeBound { span });
+ self.set_tainted_by_errors(tcx.dcx().emit_err(AmbiguousLifetimeBound { span }));
}
Some(r)
}
diff --git a/compiler/rustc_hir_analysis/src/astconv/object_safety.rs b/compiler/rustc_hir_analysis/src/astconv/object_safety.rs
index ea2f5f50b5c60..f77f250cd288e 100644
--- a/compiler/rustc_hir_analysis/src/astconv/object_safety.rs
+++ b/compiler/rustc_hir_analysis/src/astconv/object_safety.rs
@@ -116,7 +116,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
for more information on them, visit \
",
);
- err.emit();
+ self.set_tainted_by_errors(err.emit());
}
if regular_traits.is_empty() && auto_traits.is_empty() {
@@ -127,6 +127,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
.map(|trait_ref| tcx.def_span(trait_ref));
let reported =
tcx.dcx().emit_err(TraitObjectDeclaredWithNoTraits { span, trait_alias_span });
+ self.set_tainted_by_errors(reported);
return Ty::new_error(tcx, reported);
}
@@ -290,7 +291,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
if references_self {
let def_id = i.bottom().0.def_id();
- struct_span_code_err!(
+ let reported = struct_span_code_err!(
tcx.dcx(),
i.bottom().1,
E0038,
@@ -303,6 +304,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
.error_msg(),
)
.emit();
+ self.set_tainted_by_errors(reported);
}
ty::ExistentialTraitRef { def_id: trait_ref.def_id, args }
@@ -389,6 +391,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
} else {
err.emit()
};
+ self.set_tainted_by_errors(e);
ty::Region::new_error(tcx, e)
})
}
diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs
index c9f89a0c3ef32..e557f36037b6c 100644
--- a/compiler/rustc_hir_analysis/src/collect.rs
+++ b/compiler/rustc_hir_analysis/src/collect.rs
@@ -35,6 +35,7 @@ use rustc_target::spec::abi;
use rustc_trait_selection::infer::InferCtxtExt;
use rustc_trait_selection::traits::error_reporting::suggestions::NextTypeParamName;
use rustc_trait_selection::traits::ObligationCtxt;
+use std::cell::Cell;
use std::iter;
use std::ops::Bound;
@@ -119,6 +120,7 @@ pub fn provide(providers: &mut Providers) {
pub struct ItemCtxt<'tcx> {
tcx: TyCtxt<'tcx>,
item_def_id: LocalDefId,
+ tainted_by_errors: Cell