Skip to content
Open
182 changes: 77 additions & 105 deletions compiler/rustc_ast_lowering/src/delegation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,8 @@ use smallvec::SmallVec;
use crate::delegation::generics::{GenericsGenerationResult, GenericsGenerationResults};
use crate::errors::{CycleInDelegationSignatureResolution, UnresolvedDelegationCallee};
use crate::{
AllowReturnTypeNotation, GenericArgsMode, ImplTraitContext, ImplTraitPosition, LoweringContext,
ParamMode, ResolverAstLoweringExt,
AllowReturnTypeNotation, ImplTraitContext, ImplTraitPosition, LoweringContext, ParamMode,
ResolverAstLoweringExt,
};

mod generics;
Expand Down Expand Up @@ -146,24 +146,31 @@ impl<'hir> LoweringContext<'_, 'hir> {
let mut generics =
self.uplift_delegation_generics(delegation, sig_id, item_id, is_method);

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

let decl =
self.lower_delegation_decl(sig_id, param_count, c_variadic, span, &generics);
let decl = self.lower_delegation_decl(
sig_id,
param_count,
c_variadic,
span,
&generics,
delegation.id,
call_expr_id,
);

let sig = self.lower_delegation_sig(sig_id, decl, span);
let ident = self.lower_ident(delegation.ident);

let generics = self.arena.alloc(hir::Generics {
has_where_clause_predicates: false,
params: self.arena.alloc_from_iter(generics.all_params(span, self)),
predicates: self.arena.alloc_from_iter(generics.all_predicates(span, self)),
params: self.arena.alloc_from_iter(generics.all_params()),
predicates: self.arena.alloc_from_iter(generics.all_predicates()),
span,
where_clause_span: span,
});
Expand Down Expand Up @@ -282,6 +289,8 @@ impl<'hir> LoweringContext<'_, 'hir> {
c_variadic: bool,
span: Span,
generics: &GenericsGenerationResults<'hir>,
call_path_node_id: NodeId,
call_expr_id: HirId,
) -> &'hir hir::FnDecl<'hir> {
// The last parameter in C variadic functions is skipped in the signature,
// like during regular lowering.
Expand All @@ -299,7 +308,9 @@ impl<'hir> LoweringContext<'_, 'hir> {
hir_id: self.next_id(),
kind: hir::TyKind::InferDelegation(hir::InferDelegation::Sig(
sig_id,
hir::InferDelegationSig::Output(self.arena.alloc(hir::DelegationGenerics {
hir::InferDelegationSig::Output(self.arena.alloc(hir::DelegationInfo {
call_expr_id,
call_path_res: self.get_resolution_id(call_path_node_id),
Comment thread
petrochenkov marked this conversation as resolved.
child_args_segment_id: generics.child.args_segment_id,
parent_args_segment_id: generics.parent.args_segment_id,
self_ty_id: generics.self_ty_id,
Expand Down Expand Up @@ -402,10 +413,11 @@ impl<'hir> LoweringContext<'_, 'hir> {
param_count: usize,
generics: &mut GenericsGenerationResults<'hir>,
span: Span,
) -> BodyId {
) -> (BodyId, HirId) {
let block = delegation.body.as_deref();
let mut call_expr_id = HirId::INVALID;

self.lower_body(|this| {
let block_id = self.lower_body(|this| {
let mut parameters: Vec<hir::Param<'_>> = Vec::with_capacity(param_count);
let mut args: Vec<hir::Expr<'_>> = Vec::with_capacity(param_count);

Expand Down Expand Up @@ -442,10 +454,17 @@ impl<'hir> LoweringContext<'_, 'hir> {
args.push(this.lower_target_expr(&block));
}

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

call_expr_id = hir_id;

(this.arena.alloc_from_iter(parameters), final_expr)
})
});

debug_assert_ne!(call_expr_id, HirId::INVALID);

(block_id, call_expr_id)
}

// FIXME(fn_delegation): Alternatives for target expression lowering:
Expand All @@ -461,108 +480,59 @@ impl<'hir> LoweringContext<'_, 'hir> {
self.mk_expr(hir::ExprKind::Block(block, None), block.span)
}

// Generates expression for the resulting body. If possible, `MethodCall` is used
// to allow autoref/autoderef for target expression. For example in:
//
// trait Trait : Sized {
// fn by_value(self) -> i32 { 1 }
// fn by_mut_ref(&mut self) -> i32 { 2 }
// fn by_ref(&self) -> i32 { 3 }
// }
//
// struct NewType(SomeType);
// impl Trait for NewType {
// reuse Trait::* { self.0 }
// }
//
// `self.0` will automatically coerce.
fn finalize_body_lowering(
&mut self,
delegation: &Delegation,
args: Vec<hir::Expr<'hir>>,
generics: &mut GenericsGenerationResults<'hir>,
span: Span,
) -> hir::Expr<'hir> {
let args = self.arena.alloc_from_iter(args);

let has_generic_args =
delegation.path.segments.iter().rev().skip(1).any(|segment| segment.args.is_some());

let call = if self
.get_resolution_id(delegation.id)
.map(|def_id| self.is_method(def_id, span))
.unwrap_or_default()
&& delegation.qself.is_none()
&& !has_generic_args
&& !args.is_empty()
{
let ast_segment = delegation.path.segments.last().unwrap();
let segment = self.lower_path_segment(
delegation.path.span,
ast_segment,
ParamMode::Optional,
GenericArgsMode::Err,
ImplTraitContext::Disallowed(ImplTraitPosition::Path),
None,
);

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

self.arena.alloc(hir::Expr {
hir_id: self.next_id(),
kind: hir::ExprKind::MethodCall(segment, &args[0], &args[1..], span),
span,
})
} else {
let path = self.lower_qpath(
delegation.id,
&delegation.qself,
&delegation.path,
ParamMode::Optional,
AllowReturnTypeNotation::No,
ImplTraitContext::Disallowed(ImplTraitPosition::Path),
None,
);

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)| {
if idx + 2 == len {
self.process_segment(span, segment, &mut generics.parent)
} else if idx + 1 == len {
self.process_segment(span, segment, &mut generics.child)
} else {
segment.clone()
}
}),
);

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

hir::QPath::TypeRelative(ty, self.arena.alloc(segment))
}
};
) -> (hir::Expr<'hir>, HirId) {
let path = self.lower_qpath(
delegation.id,
&delegation.qself,
&delegation.path,
ParamMode::Optional,
AllowReturnTypeNotation::No,
ImplTraitContext::Disallowed(ImplTraitPosition::Path),
None,
);

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)| {
if idx + 2 == len {
self.process_segment(span, segment, &mut generics.parent)
} else if idx + 1 == len {
self.process_segment(span, segment, &mut generics.child)
} else {
segment.clone()
}
}),
);

generics.self_ty_id = match new_path {
hir::QPath::Resolved(ty, _) => ty,
hir::QPath::TypeRelative(ty, _) => Some(ty),
hir::QPath::Resolved(ty, self.arena.alloc(new_path))
}
.map(|ty| ty.hir_id);
hir::QPath::TypeRelative(ty, segment) => {
let segment = self.process_segment(span, segment, &mut generics.child);

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))
hir::QPath::TypeRelative(ty, self.arena.alloc(segment))
}
};

generics.self_ty_id = match new_path {
hir::QPath::Resolved(ty, _) => ty,
hir::QPath::TypeRelative(ty, _) => Some(ty),
}
.map(|ty| ty.hir_id);

let callee_path = self.arena.alloc(self.mk_expr(hir::ExprKind::Path(new_path), span));
let args = self.arena.alloc_from_iter(args);
let call = 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 @@ -572,7 +542,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
targeted_by_break: false,
});

self.mk_expr(hir::ExprKind::Block(block, None), span)
(self.mk_expr(hir::ExprKind::Block(block, None), span), call.hir_id)
}

fn process_segment(
Expand All @@ -583,8 +553,10 @@ impl<'hir> LoweringContext<'_, 'hir> {
) -> hir::PathSegment<'hir> {
let details = result.generics.args_propagation_details();

// Always uplift generic params, because if they are not empty then they
// should be generated in delegation.
let generics = result.generics.into_hir_generics(self, span);
let segment = if details.should_propagate {
let generics = result.generics.into_hir_generics(self, span);
let args = generics.into_generic_args(self, span);

// Needed for better error messages (`trait-impl-wrong-args-count.rs` test).
Expand Down
45 changes: 11 additions & 34 deletions compiler/rustc_ast_lowering/src/delegation/generics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -171,22 +171,9 @@ impl<'hir> GenericsGenerationResult<'hir> {
}

impl<'hir> GenericsGenerationResults<'hir> {
pub(super) fn all_params(
&mut self,
span: Span,
ctx: &mut LoweringContext<'_, 'hir>,
) -> impl Iterator<Item = hir::GenericParam<'hir>> {
// Now we always call `into_hir_generics` both on child and parent,
// however in future we would not do that, when scenarios like
// method call will be supported (if HIR generics were not obtained
// then it means that we did not propagated them, thus we do not need
// to generate params).
let mut create_params = |result: &mut GenericsGenerationResult<'hir>| {
result.generics.into_hir_generics(ctx, span).hir_generics_or_empty().params
};

let parent = create_params(&mut self.parent);
let child = create_params(&mut self.child);
pub(super) fn all_params(&self) -> impl Iterator<Item = hir::GenericParam<'hir>> {
let parent = self.parent.generics.hir_generics_or_empty().params;
let child = self.child.generics.hir_generics_or_empty().params;

// Order generics, first we have parent and child lifetimes,
// then parent and child types and consts.
Expand All @@ -205,24 +192,14 @@ impl<'hir> GenericsGenerationResults<'hir> {
/// and `generate_lifetime_predicate` functions) we need to add them to delegation generics.
/// Those predicates will not affect resulting predicate inheritance and folding
/// in `rustc_hir_analysis`, as we inherit all predicates from delegation signature.
pub(super) fn all_predicates(
&mut self,
span: Span,
ctx: &mut LoweringContext<'_, 'hir>,
) -> impl Iterator<Item = hir::WherePredicate<'hir>> {
// Now we always call `into_hir_generics` both on child and parent,
// however in future we would not do that, when scenarios like
// method call will be supported (if HIR generics were not obtained
// then it means that we did not propagated them, thus we do not need
// to generate predicates).
let mut create_predicates = |result: &mut GenericsGenerationResult<'hir>| {
result.generics.into_hir_generics(ctx, span).hir_generics_or_empty().predicates
};

let parent = create_predicates(&mut self.parent);
let child = create_predicates(&mut self.child);

parent.into_iter().chain(child).copied()
pub(super) fn all_predicates(&self) -> impl Iterator<Item = hir::WherePredicate<'hir>> {
self.parent
.generics
.hir_generics_or_empty()
.predicates
.into_iter()
.chain(self.child.generics.hir_generics_or_empty().predicates)
.copied()
}
}

Expand Down
11 changes: 6 additions & 5 deletions compiler/rustc_hir/src/hir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3772,9 +3772,10 @@ pub enum OpaqueTyOrigin<D> {
},
}

// Ids of parent (or child) path segment that contains user-specified args
#[derive(Debug, Clone, Copy, PartialEq, Eq, StableHash)]
pub struct DelegationGenerics {
pub struct DelegationInfo {
pub call_expr_id: HirId,
pub call_path_res: Option<DefId>,
pub parent_args_segment_id: Option<HirId>,
pub child_args_segment_id: Option<HirId>,
pub self_ty_id: Option<HirId>,
Expand All @@ -3784,8 +3785,8 @@ pub struct DelegationGenerics {
#[derive(Debug, Clone, Copy, PartialEq, Eq, StableHash)]
pub enum InferDelegationSig<'hir> {
Input(usize),
// Place generics info here, as we always specify output type for delegations.
Output(&'hir DelegationGenerics),
// Place delegation info here, as we always specify output type for delegations.
Output(&'hir DelegationInfo),
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, StableHash)]
Expand Down Expand Up @@ -4072,7 +4073,7 @@ impl<'hir> FnDecl<'hir> {
None
}

pub fn opt_delegation_generics(&self) -> Option<&'hir DelegationGenerics> {
pub fn opt_delegation_info(&self) -> Option<&'hir DelegationInfo> {
if let FnRetTy::Return(ty) = self.output
&& let TyKind::InferDelegation(InferDelegation::Sig(_, kind)) = ty.kind
&& let InferDelegationSig::Output(generics) = kind
Expand Down
Loading
Loading