Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
6a7a8d1
gnullvm: always link libunwind statically
mati865 Jul 22, 2026
9acbf04
gnullvm: stop handling crt-static
mati865 Jul 22, 2026
6e0d85d
gnullvm: stop shipping libunwind import lib
mati865 Jul 22, 2026
e2eb974
gnullvm: document the need for static libunwind
mati865 Aug 7, 2026
c321d90
offload: automate manual clang-linker-wrapper step
sgasho Sep 4, 2026
18ada5c
compile bitcode in device.bin beforehand in order to avoid LLVM JIT, …
sgasho Sep 6, 2026
f9017b1
add rpath
sgasho Sep 6, 2026
ff680e2
compile device image without adding extra binaries
sgasho Sep 7, 2026
2c4265a
Supporting delegations to inherent functions
aerooneqq Sep 8, 2026
7ce50f8
Add test for soundness issue on new solver
lsunsi Sep 8, 2026
265ca10
Make ConstKind Placeholder also check ConstArgHasType
lsunsi Sep 7, 2026
8622679
limit the api of fold_predicate and visit_predicate
jdonszelmann Sep 4, 2026
a80f20d
Keep type-op region constraints in borrowck
Dnreikronos Sep 8, 2026
16f306c
Rollup merge of #162309 - sgasho:offload-clang-linker-wrapper, r=ZuseZ4
JonathanBrouwer Sep 8, 2026
78280f7
Rollup merge of #160505 - aerooneqq:delegation-inherent-methods, r=pe…
JonathanBrouwer Sep 8, 2026
37719fa
Rollup merge of #160712 - mati865:gnullvm-static-libunwind, r=petroch…
JonathanBrouwer Sep 8, 2026
9318843
Rollup merge of #161423 - Dnreikronos:trait_selection/preserve_type_o…
JonathanBrouwer Sep 8, 2026
d8dd9f1
Rollup merge of #162461 - jdonszelmann:restrict-fold-predicate, r=Box…
JonathanBrouwer Sep 8, 2026
faf7381
Rollup merge of #162475 - lsunsi:issue296, r=BoxyUwU
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
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