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
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 @@ -144,24 +144,31 @@ impl<'hir> LoweringContext<'_, 'hir> {

let mut generics = self.uplift_delegation_generics(delegation, sig_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 @@ -280,6 +287,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 @@ -297,7 +306,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 @@ -400,10 +411,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 @@ -440,10 +452,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 @@ -459,108 +478,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 @@ -570,7 +540,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 @@ -581,8 +551,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 @@ -3864,9 +3864,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 @@ -3876,8 +3877,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 @@ -4164,7 +4165,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