Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,6 @@ use rustc_ast::*;
use rustc_attr_parsing::{AttributeParser, ShouldEmit};
use rustc_data_structures::fx::FxHashSet;
use rustc_errors::ErrorGuaranteed;
use rustc_hir::Target;
use rustc_hir::attrs::{AttributeKind, InlineAttr};
use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_middle::span_bug;
Expand All @@ -56,9 +55,12 @@ use rustc_span::{DUMMY_SP, Ident, Span, Symbol};
use smallvec::SmallVec;
use {rustc_ast as ast, rustc_hir as hir};

use super::{GenericArgsMode, ImplTraitContext, LoweringContext, ParamMode};
use crate::delegation::generics::{GenericsGenerationResult, GenericsGenerationResults};
use crate::errors::{CycleInDelegationSignatureResolution, UnresolvedDelegationCallee};
use crate::{AllowReturnTypeNotation, ImplTraitPosition, ResolverAstLoweringExt};
use crate::{
AllowReturnTypeNotation, GenericArgsMode, ImplTraitContext, ImplTraitPosition, LoweringContext,
ParamMode, ResolverAstLoweringExt,
};

pub(crate) struct DelegationResults<'hir> {
pub body_id: hir::BodyId,
Expand Down Expand Up @@ -107,7 +109,7 @@ type DelegationIdsVec = SmallVec<[DefId; 1]>;
// As delegations can now refer to another delegation, we have a delegation path
// of the following type: reuse (current delegation) <- reuse (delegee_id) <- ... <- reuse <- function (root_function_id).
// In its most basic and widely used form: reuse (current delegation) <- function (delegee_id, root_function_id)
struct DelegationIds {
pub(super) struct DelegationIds {
path: DelegationIdsVec,
}

Expand All @@ -118,13 +120,13 @@ impl DelegationIds {
}

// Id of the first function in (non)local crate that is being reused
fn root_function_id(&self) -> DefId {
pub(super) fn root_function_id(&self) -> DefId {
*self.path.last().expect("Ids vector can't be empty")
}

// Id of the first definition which is being reused,
// can be either function, in this case `root_id == delegee_id`, or other delegation
fn delegee_id(&self) -> DefId {
pub(super) fn delegee_id(&self) -> DefId {
*self.path.first().expect("Ids vector can't be empty")
}
}
Expand Down Expand Up @@ -184,18 +186,42 @@ impl<'hir> LoweringContext<'_, 'hir> {
// we need a function to extract this information
let (param_count, c_variadic) = self.param_count(root_function_id);

let mut generics = self.lower_delegation_generics(delegation, &ids, item_id);

let body_id = self.lower_delegation_body(
delegation,
item_id,
is_method,
param_count,
&mut generics,
span,
);

let ident = self.lower_ident(delegation.ident);

// Here we use `delegee_id`, as this id will then be used to calculate parent for generics
// inheritance, and we want this id to point on a delegee, not on the original
// function (see https://github.com/rust-lang/rust/issues/150152#issuecomment-3674834654)
let decl = self.lower_delegation_decl(delegee_id, param_count, c_variadic, span);
let decl = self.lower_delegation_decl(
delegee_id,
param_count,
c_variadic,
span,
&generics,
);

// Here we pass `root_function_id` as we want to inherit signature (including consts, async)
// from the root function that started delegation
let sig = self.lower_delegation_sig(root_function_id, decl, span);

let body_id = self.lower_delegation_body(delegation, is_method, param_count, span);
let ident = self.lower_ident(delegation.ident);
let generics = self.lower_delegation_generics(span);
let generics = self.arena.alloc(hir::Generics {
has_where_clause_predicates: false,
params: self.arena.alloc_from_iter(generics.all_params(item_id, span, self)),
predicates: self.arena.alloc_from_iter(generics.all_predicates()),
span,
where_clause_span: span,
});

DelegationResults { body_id, sig, ident, generics }
}
Err(err) => self.generate_delegation_error(err, span, delegation),
Expand Down Expand Up @@ -292,7 +318,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
self.tcx.sess,
attrs,
None,
Target::Fn,
hir::Target::Fn,
DUMMY_SP,
DUMMY_NODE_ID,
Some(self.tcx.features()),
Expand Down Expand Up @@ -357,20 +383,10 @@ impl<'hir> LoweringContext<'_, 'hir> {
}
}

fn get_resolution_id(&self, node_id: NodeId) -> Option<DefId> {
pub(super) fn get_resolution_id(&self, node_id: NodeId) -> Option<DefId> {
self.resolver.get_partial_res(node_id).and_then(|r| r.expect_full_res().opt_def_id())
}

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,
})
}

// Function parameter count, including C variadic `...` if present.
fn param_count(&self, def_id: DefId) -> (usize, bool /*c_variadic*/) {
if let Some(local_sig_id) = def_id.as_local() {
Expand All @@ -390,6 +406,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
param_count: usize,
c_variadic: bool,
span: Span,
generics: &GenericsGenerationResults<'hir>,
) -> &'hir hir::FnDecl<'hir> {
// The last parameter in C variadic functions is skipped in the signature,
// like during regular lowering.
Expand All @@ -402,7 +419,12 @@ impl<'hir> LoweringContext<'_, 'hir> {

let output = self.arena.alloc(hir::Ty {
hir_id: self.next_id(),
kind: hir::TyKind::InferDelegation(sig_id, hir::InferDelegationKind::Output),
kind: hir::TyKind::InferDelegation(
sig_id,
hir::InferDelegationKind::Output(
self.arena.alloc(generics.create_hir_delegation_generics()),
),
),
span,
});

Expand Down Expand Up @@ -457,6 +479,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
abi: sig.abi,
}
};

hir::FnSig { decl, header, span }
}

Expand Down Expand Up @@ -498,6 +521,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
} else {
Symbol::intern(&format!("arg{idx}"))
};

let segments = self.arena.alloc_from_iter(iter::once(hir::PathSegment {
ident: Ident::with_dummy_span(name),
hir_id: self.next_id(),
Expand All @@ -513,8 +537,10 @@ impl<'hir> LoweringContext<'_, 'hir> {
fn lower_delegation_body(
&mut self,
delegation: &Delegation,
item_id: NodeId,
is_method: bool,
param_count: usize,
generics: &mut GenericsGenerationResults<'hir>,
span: Span,
) -> BodyId {
let block = delegation.body.as_deref();
Expand Down Expand Up @@ -545,7 +571,8 @@ impl<'hir> LoweringContext<'_, 'hir> {
args.push(arg);
}

let final_expr = this.finalize_body_lowering(delegation, args, span);
let final_expr = this.finalize_body_lowering(delegation, item_id, args, generics, span);

(this.arena.alloc_from_iter(parameters), final_expr)
})
}
Expand Down Expand Up @@ -581,7 +608,9 @@ impl<'hir> LoweringContext<'_, 'hir> {
fn finalize_body_lowering(
&mut self,
delegation: &Delegation,
item_id: NodeId,
args: Vec<hir::Expr<'hir>>,
generics: &mut GenericsGenerationResults<'hir>,
span: Span,
) -> hir::Expr<'hir> {
let args = self.arena.alloc_from_iter(args);
Expand All @@ -606,6 +635,10 @@ impl<'hir> LoweringContext<'_, 'hir> {
ImplTraitContext::Disallowed(ImplTraitPosition::Path),
None,
);

// FIXME(fn_delegation): proper support for parent generics propagation
// in method call scenario.
let segment = self.process_segment(item_id, span, &segment, &mut generics.child, false);
let segment = self.arena.alloc(segment);

self.arena.alloc(hir::Expr {
Expand All @@ -624,9 +657,41 @@ impl<'hir> LoweringContext<'_, 'hir> {
None,
);

let callee_path = self.arena.alloc(self.mk_expr(hir::ExprKind::Path(path), span));
let new_path = match path {
hir::QPath::Resolved(ty, path) => {
let mut new_path = path.clone();
let len = new_path.segments.len();

new_path.segments = self.arena.alloc_from_iter(
new_path.segments.iter().enumerate().map(|(idx, segment)| {
let mut process_segment = |result, add_lifetimes| {
self.process_segment(item_id, span, segment, result, add_lifetimes)
};

if idx + 2 == len {
process_segment(&mut generics.parent, true)
} else if idx + 1 == len {
process_segment(&mut generics.child, false)
} else {
segment.clone()
}
}),
);

hir::QPath::Resolved(ty, self.arena.alloc(new_path))
}
hir::QPath::TypeRelative(ty, segment) => {
let segment =
self.process_segment(item_id, span, segment, &mut generics.child, false);

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

let callee_path = self.arena.alloc(self.mk_expr(hir::ExprKind::Path(new_path), span));
self.arena.alloc(self.mk_expr(hir::ExprKind::Call(callee_path, args), span))
};

let block = self.arena.alloc(hir::Block {
stmts: &[],
expr: Some(call),
Expand All @@ -639,14 +704,43 @@ impl<'hir> LoweringContext<'_, 'hir> {
self.mk_expr(hir::ExprKind::Block(block, None), span)
}

fn process_segment(
&mut self,
item_id: NodeId,
span: Span,
segment: &hir::PathSegment<'hir>,
result: &mut GenericsGenerationResult<'hir>,
add_lifetimes: bool,
) -> hir::PathSegment<'hir> {
// The first condition is needed when there is SelfAndUserSpecified case,
// we don't want to propagate generics params in this situation.
let segment = if !result.generics.is_user_specified()
&& let Some(args) = result
.generics
.into_hir_generics(self, item_id, span)
.into_generic_args(self, add_lifetimes, span)
{
let mut new_segment = segment.clone();
new_segment.args = Some(args);

new_segment
} else {
segment.clone()
};

if result.generics.is_user_specified() {
result.args_segment_id = Some(segment.hir_id);
}

segment
}

fn generate_delegation_error(
&mut self,
err: ErrorGuaranteed,
span: Span,
delegation: &Delegation,
) -> DelegationResults<'hir> {
let generics = self.lower_delegation_generics(span);

let decl = self.arena.alloc(hir::FnDecl {
inputs: &[],
output: hir::FnRetTy::DefaultReturn(span),
Expand All @@ -664,10 +758,10 @@ impl<'hir> LoweringContext<'_, 'hir> {
let body_expr = match delegation.body.as_ref() {
Some(box block) => {
// Generates a block when we failed to resolve delegation, where a target expression is its only statement,
// thus there will be no ICEs on further stages of analysis (see #144594)
// thus there will be no ICEs on further stages of analysis (see #144594).

// As we generate a void function we want to convert target expression to statement to avoid additional
// errors, such as mismatched return type
// errors, such as mismatched return type.
let stmts = this.arena.alloc_from_iter([hir::Stmt {
hir_id: this.next_id(),
kind: rustc_hir::StmtKind::Semi(
Expand All @@ -693,6 +787,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
(&[], this.mk_expr(body_expr, span))
});

let generics = hir::Generics::empty();
DelegationResults { ident, generics, body_id, sig }
}

Expand Down
Loading
Loading