Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
98f4067
mir: validate Move call arguments are locals or box derefs
rabindra789 Aug 6, 2026
84963f8
run `extern "tail"` with `byval` argument test
folkertdev Aug 28, 2026
7768834
Add regression test for item-local diagnostic attribute lint levels
chenyukang Sep 7, 2026
38e3714
windows-gnu: document libgcc requirement
mati865 Sep 7, 2026
9dee1dc
Update books
rustbot Sep 7, 2026
fa2850e
misc typo fixes
ada4a Aug 24, 2026
2827a30
remove outdated docs
ada4a Aug 24, 2026
0db592d
realize that `bounds` works a bit differently than advertised
ada4a Aug 24, 2026
ada4f67
add tests for `#[derive(GenericTypeVisitable)]` and `bounds`
ada4a Sep 7, 2026
2c4265a
Supporting delegations to inherent functions
aerooneqq Sep 8, 2026
8463342
docs(time): replace "method" with "function"
sorairolake Sep 8, 2026
9bf6ad8
Fix duplicate thanks entry
JonathanBrouwer Sep 8, 2026
38d520a
Rollup merge of #160505 - aerooneqq:delegation-inherent-methods, r=pe…
JonathanBrouwer Sep 8, 2026
7495f9d
Rollup merge of #160651 - rabindra789:fix/mir-verifier-move-call-args…
JonathanBrouwer Sep 8, 2026
308bb02
Rollup merge of #161806 - ada4a:push-olrruxoktqnl, r=JonathanBrouwer
JonathanBrouwer Sep 8, 2026
c346c2d
Rollup merge of #161912 - folkertdev:extern-tail-x86-byval, r=WaffleL…
JonathanBrouwer Sep 8, 2026
1663ff8
Rollup merge of #162435 - mati865:windows-gnu-libgcc-doc, r=nnethercote
JonathanBrouwer Sep 8, 2026
d5875ad
Rollup merge of #162439 - rustbot:docs-update, r=traviscross
JonathanBrouwer Sep 8, 2026
2447c55
Rollup merge of #162451 - chenyukang:yukang-fix-135772-local-diagnost…
JonathanBrouwer Sep 8, 2026
8b05fb1
Rollup merge of #162459 - sorairolake:fix-method-to-function, r=Darksonn
JonathanBrouwer Sep 8, 2026
9534920
Rollup merge of #162465 - JonathanBrouwer:fix-mailmap, r=JonathanBrouwer
JonathanBrouwer Sep 8, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .mailmap
Original file line number Diff line number Diff line change
Expand Up @@ -350,6 +350,7 @@ John Van Enk <vanenkj@gmail.com>
Jon Gjengset <jon@thesquareplanet.com> <jongje@amazon.com>
Jonas Tepe <jonasprogrammer@gmail.com>
Jonathan Bailey <jbailey@mozilla.com> <jbailey@jbailey-20809.local>
Jonathan Brouwer <jonathantbrouwer@gmail.com> <jonathan.brouwer@technolution.nl>
Jonathan Chan Kwan Yin <sofe2038@gmail.com>
Jonathan L <Xmasreturns@users.noreply.github.com>
Jonathan S <gereeter@gmail.com> Jonathan S <gereeter+code@gmail.com>
Expand Down
8 changes: 8 additions & 0 deletions compiler/rustc_ast/src/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -294,6 +294,14 @@ impl GenericArg {
GenericArg::Const(ct) => ct.value.span,
}
}

pub fn is_maybe_parenthesised_infer(&self) -> bool {
match self {
GenericArg::Lifetime(lt) => lt.ident.name == kw::UnderscoreLifetime,
GenericArg::Type(ty) => ty.is_maybe_parenthesised_infer(),
GenericArg::Const(_) => false,
}
}
}

/// A path like `Foo<'a, T>`.
Expand Down
93 changes: 76 additions & 17 deletions compiler/rustc_ast_lowering/src/delegation/generics.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use std::assert_matches;

use hir::HirId;
use hir::def::{DefKind, Res};
use rustc_ast::*;
Expand All @@ -11,7 +13,10 @@ use rustc_span::{ErrorGuaranteed, Ident, Span, sym};

use crate::LoweringContext;
use crate::delegation::resolution::resolver::DelegationResolver;
use crate::diagnostics::DelegationInfersMismatch;
use crate::diagnostics::{
DelegationInfersMismatch, DelegationToInherentImplMustContainParentGenerics,
DelegationToInherentImplParentContainsInfer,
};

#[derive(Debug, Clone, Copy, Eq, PartialEq)]
pub(super) enum GenericsPosition {
Expand All @@ -25,6 +30,7 @@ pub(super) enum GenericArgSlot<T> {
Generate(T, Option<usize> /* Infer arg index from AST */),
}

#[derive(Debug)]
pub(super) struct DelegationGenerics<T> {
data: T,
pos: GenericsPosition,
Expand Down Expand Up @@ -57,11 +63,13 @@ impl<'hir> DelegationGenerics<TyGenerics<'hir>> {
/// meaning we did not propagate them and thus we do not need to generate generic params
/// (i.e., method call scenarios), in such a case this approach helps
/// a lot as if `into_hir_generics` will not be called then uplifting will not happen.
#[derive(Debug)]
pub(super) enum HirOrTyGenerics<'hir> {
Ty(DelegationGenerics<TyGenerics<'hir>>),
Hir(DelegationGenerics<&'hir hir::Generics<'hir>>),
}

#[derive(Debug)]
pub(super) struct GenericsGenerationResult<'hir> {
pub(super) generics: HirOrTyGenerics<'hir>,
pub(super) args_segment_id: HirId,
Expand All @@ -80,6 +88,7 @@ pub(super) struct GenericsGenerationResults<'hir> {
pub(super) self_ty_propagation_kind: Option<hir::DelegationSelfTyPropagationKind>,
}

#[derive(Debug)]
pub(super) struct DelegationGenericArgsIterator<'hir> {
index: usize = Default::default(),
params: &'hir [hir::GenericParam<'hir>],
Expand Down Expand Up @@ -145,6 +154,7 @@ impl<'hir> DelegationGenericArgsIterator<'hir> {
ctx: &mut LoweringContext<'_, 'hir>,
) -> Vec<hir::GenericArg<'hir>> {
let mut args = vec![];

while let Some(arg) = self.next(ctx, |ctx| ctx.next_id()) {
args.push(arg);
}
Expand Down Expand Up @@ -238,6 +248,7 @@ impl<'hir> GenericsGenerationResult<'hir> {
}
}

#[derive(Debug)]
enum ParentSegmentArgs<'a> {
/// Parent segment is valid and generic args are specified:
/// `reuse Trait::<'static, ()>::foo;`.
Expand Down Expand Up @@ -273,7 +284,7 @@ struct GenericsResolution<'a, 'tcx> {
/// `reuse <_ as Trait>::foo;`.
qself_is_infer: bool,
/// Whether we should generate `Self` generic param.
generate_self: bool,
generate_free_to_trait_self: bool,
}

impl<'hir> DelegationResolver<'_, 'hir> {
Expand All @@ -288,8 +299,7 @@ impl<'hir> DelegationResolver<'_, 'hir> {
let delegation_in_free_ctx =
!matches!(delegation_parent_kind, DefKind::Trait | DefKind::Impl { .. });

let sig_parent = tcx.parent(sig_id);
let sig_in_trait = matches!(tcx.def_kind(sig_parent), DefKind::Trait);
let sig_in_trait = matches!(tcx.def_kind(tcx.parent(sig_id)), DefKind::Trait);
let free_to_trait_delegation = delegation_in_free_ctx && sig_in_trait;

let mut sig_parent_params: &[ty::GenericParamDef] = &[];
Expand All @@ -301,8 +311,13 @@ impl<'hir> DelegationResolver<'_, 'hir> {

let parent_args = if let [.., parent_segment, _] = &delegation.path.segments[..] {
let res = self.get_resolution_id(parent_segment.id)?;
if matches!(tcx.def_kind(res), DefKind::Trait | DefKind::TraitAlias) {
sig_parent_params = &tcx.generics_of(sig_parent).own_params;
if !matches!(tcx.def_kind(res), DefKind::Mod) {
assert_matches!(
tcx.def_kind(res),
DefKind::Trait | DefKind::Struct | DefKind::Enum
);

sig_parent_params = &tcx.generics_of(res).own_params;
self.get_user_args(parent_segment)
.map(|args| ParentSegmentArgs::Specified(args))
.unwrap_or(ParentSegmentArgs::NotSpecified)
Expand All @@ -319,7 +334,8 @@ impl<'hir> DelegationResolver<'_, 'hir> {
qself_is_none,
qself_is_infer,
free_to_trait_delegation,
generate_self: free_to_trait_delegation && (qself_is_none || qself_is_infer),
generate_free_to_trait_self: free_to_trait_delegation
&& (qself_is_none || qself_is_infer),
trait_impl: matches!(delegation_parent_kind, DefKind::Impl { of_trait: true }),
sig_child_params: &tcx.generics_of(sig_id).own_params,
child_args: self.get_user_args(
Expand Down Expand Up @@ -349,10 +365,11 @@ impl<'hir> DelegationResolver<'_, 'hir> {
&self,
delegation: &Delegation,
sig_id: DefId,
span: Span,
) -> Result<GenericsGenerationResults<'hir>, ErrorGuaranteed> {
let res @ GenericsResolution {
trait_impl,
generate_self,
generate_free_to_trait_self,
sig_child_params,
sig_parent_params,
..
Expand All @@ -376,20 +393,27 @@ impl<'hir> DelegationResolver<'_, 'hir> {
return Ok(GenericsGenerationResults { parent, child, self_ty_propagation_kind: None });
}

self.check_delegation_to_inherent_impl(&res.parent_args, sig_id, span)?;

let tcx = self.tcx();

// If parent is inherent impl then there is no `Self` param to skip, so add additional check.
let skip_self =
!generate_free_to_trait_self && tcx.def_kind(tcx.parent(sig_id)) == DefKind::Trait;

let parent_generics = match res.parent_args {
ParentSegmentArgs::Specified(args) => DelegationGenerics {
data: Self::create_slots_from_args(
tcx,
args,
&sig_parent_params[usize::from(!generate_self)..],
generate_self,
&sig_parent_params[usize::from(skip_self)..],
generate_free_to_trait_self,
),
pos: GenericsPosition::Parent,
trait_impl,
},
ParentSegmentArgs::NotSpecified => DelegationGenerics::generate_all(
&sig_parent_params[usize::from(!generate_self)..],
&sig_parent_params[usize::from(skip_self)..],
GenericsPosition::Parent,
trait_impl,
),
Expand Down Expand Up @@ -437,6 +461,46 @@ impl<'hir> DelegationResolver<'_, 'hir> {
})
}

fn check_delegation_to_inherent_impl(
&self,
parent_args: &ParentSegmentArgs<'_>,
sig_id: DefId,
span: Span,
) -> Result<(), ErrorGuaranteed> {
let tcx = self.tcx();

if !(tcx.def_kind(sig_id) == DefKind::AssocFn
&& matches!(tcx.def_kind(tcx.parent(sig_id)), DefKind::Impl { of_trait: false }))
{
return Ok(());
}

let ty::Adt(def, _) = tcx.type_of(tcx.parent(sig_id)).skip_binder().kind() else {
unreachable!("parent of inherent function can be only struct or enum")
};

match parent_args {
ParentSegmentArgs::Invalid => unreachable!(),
ParentSegmentArgs::Specified(args) => args
.args
.iter()
.all(|arg| {
let AngleBracketedArg::Arg(arg) = arg else { return false };
!arg.is_maybe_parenthesised_infer()
})
.ok_or_else(|| {
self.tcx().dcx().emit_err(DelegationToInherentImplParentContainsInfer { span })
}),
ParentSegmentArgs::NotSpecified => match tcx.generics_of(def.did()).own_params.len() {
0 => Ok(()),
_ => Err(self
.tcx()
.dcx()
.emit_err(DelegationToInherentImplMustContainParentGenerics { span })),
},
}
}

/// Generates generic argument slots for user-specified `args` and
/// generic `params` of the signature function. This function checks whether
/// there are infers (`kw::UnderscoreLifetime` or `kw::Underscore`) in
Expand All @@ -459,12 +523,7 @@ impl<'hir> DelegationResolver<'_, 'hir> {
let params = &params[usize::from(add_first_self)..];
for (idx, (arg, param)) in args.args.iter().zip(params).enumerate() {
let AngleBracketedArg::Arg(arg) = arg else { continue };

let is_infer = match arg {
GenericArg::Lifetime(lt) => lt.ident.name == kw::UnderscoreLifetime,
GenericArg::Type(ty) => ty.is_maybe_parenthesised_infer(),
GenericArg::Const(_) => false,
};
let is_infer = arg.is_maybe_parenthesised_infer();

// If `'_` is used instead of `_` (or vice versa) we emit a meaningful
// error instead of processing this infer or leaving it as is for signature
Expand Down
37 changes: 34 additions & 3 deletions compiler/rustc_ast_lowering/src/delegation/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ use rustc_ast as ast;
use rustc_ast::*;
use rustc_hir::attrs::lang_items::LangItem;
use rustc_hir::def::DefKind;
use rustc_hir::{self as hir, FnDeclFlags};
use rustc_hir::{self as hir, FnDeclFlags, QPath};
use rustc_middle::ty::Asyncness;
use rustc_span::def_id::DefId;
use rustc_span::symbol::kw;
Expand All @@ -62,7 +62,7 @@ use crate::{

mod attributes;
mod generics;
mod resolution;
pub(crate) mod resolution;

pub(crate) struct DelegationResults<'hir> {
pub body_id: hir::BodyId,
Expand Down Expand Up @@ -416,7 +416,37 @@ impl<'hir> LoweringContext<'_, 'hir> {

hir::QPath::Resolved(ty, self.arena.alloc(new_path))
}
hir::QPath::TypeRelative(..) => unreachable!("until inherent methods are supported"),
hir::QPath::TypeRelative(mut ty, segment) => {
let mut segment = self.process_segment(span, segment, &mut generics.child);
segment.res = Res::Def(self.tcx.def_kind(res.call_path_res), res.call_path_res);

let ty_hir_id = ty.hir_id;

// Propagating child generics if needed.
ty = if let hir::TyKind::Path(QPath::Resolved(ty, path)) = ty.kind {
let mut new_path = path.clone();

new_path.segments = self.arena.alloc_from_iter(
new_path.segments.iter().enumerate().map(|(idx, segment)| {
if idx + 1 == new_path.segments.len() {
self.process_segment(span, segment, &mut generics.parent)
} else {
segment.clone()
}
}),
);

self.arena.alloc(hir::Ty {
hir_id: ty_hir_id,
span,
kind: hir::TyKind::Path(QPath::Resolved(ty, self.arena.alloc(new_path))),
})
} else {
ty
};

hir::QPath::TypeRelative(ty, self.arena.alloc(segment))
}
};

if let Some(hir::DelegationSelfTyPropagationKind::SelfTy(id)) =
Expand Down Expand Up @@ -491,6 +521,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
result.generics.into_hir_generics(self, span);

let mut segment = segment.clone();

let mut args_iter = result.generics.create_args_iterator();

let new_args = segment
Expand Down
Loading
Loading