Skip to content
Merged
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
23 changes: 11 additions & 12 deletions compiler/rustc_ast_lowering/src/delegation/generics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use rustc_hir::def_id::DefId;
use rustc_middle::ty::{GenericParamDefKind, TyCtxt};
use rustc_middle::{bug, ty};
use rustc_span::symbol::kw;
use rustc_span::{Ident, Span, sym};
use rustc_span::{ErrorGuaranteed, Ident, Span, sym};

use crate::LoweringContext;
use crate::delegation::resolution::resolver::DelegationResolver;
Expand Down Expand Up @@ -281,7 +281,7 @@ impl<'hir> DelegationResolver<'_, 'hir> {
&self,
delegation: &'a Delegation,
sig_id: DefId,
) -> GenericsResolution<'a, 'hir> {
) -> Result<GenericsResolution<'a, 'hir>, ErrorGuaranteed> {
let tcx = self.tcx();
let delegation_parent_kind = tcx.def_kind(tcx.local_parent(self.owner_id()));

Expand All @@ -300,9 +300,8 @@ impl<'hir> DelegationResolver<'_, 'hir> {
let qself_is_none = delegation.qself.is_none();

let parent_args = if let [.., parent_segment, _] = &delegation.path.segments[..] {
if let Some(res) = self.get_resolution_id(parent_segment.id)
&& matches!(tcx.def_kind(res), DefKind::Trait | DefKind::TraitAlias)
{
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;
self.get_user_args(parent_segment)
.map(|args| ParentSegmentArgs::Specified(args))
Expand All @@ -314,7 +313,7 @@ impl<'hir> DelegationResolver<'_, 'hir> {
ParentSegmentArgs::Invalid
};

GenericsResolution {
Ok(GenericsResolution {
parent_args,
sig_parent_params,
qself_is_none,
Expand All @@ -326,7 +325,7 @@ impl<'hir> DelegationResolver<'_, 'hir> {
child_args: self.get_user_args(
delegation.path.segments.last().expect("must be at least one segment"),
),
}
})
}

fn get_user_args<'a>(&self, segment: &'a PathSegment) -> Option<&'a AngleBracketedArgs> {
Expand All @@ -350,14 +349,14 @@ impl<'hir> DelegationResolver<'_, 'hir> {
&self,
delegation: &Delegation,
sig_id: DefId,
) -> GenericsGenerationResults<'hir> {
) -> Result<GenericsGenerationResults<'hir>, ErrorGuaranteed> {
let res @ GenericsResolution {
trait_impl,
generate_self,
sig_child_params,
sig_parent_params,
..
} = self.resolve_generics(delegation, sig_id);
} = self.resolve_generics(delegation, sig_id)?;

// If we are in trait impl always generate function whose generics matches
// those that are defined in trait.
Expand All @@ -374,7 +373,7 @@ impl<'hir> DelegationResolver<'_, 'hir> {

let child = GenericsGenerationResult::new(child);

return GenericsGenerationResults { parent, child, self_ty_propagation_kind: None };
return Ok(GenericsGenerationResults { parent, child, self_ty_propagation_kind: None });
}

let tcx = self.tcx();
Expand Down Expand Up @@ -421,7 +420,7 @@ impl<'hir> DelegationResolver<'_, 'hir> {
DelegationGenerics::generate_all(sig_child_params, GenericsPosition::Child, trait_impl)
};

GenericsGenerationResults {
Ok(GenericsGenerationResults {
parent: GenericsGenerationResult::new(parent_generics),
child: GenericsGenerationResult::new(child_generics),
self_ty_propagation_kind: match res.free_to_trait_delegation {
Expand All @@ -435,7 +434,7 @@ impl<'hir> DelegationResolver<'_, 'hir> {
}),
false => None,
},
}
})
}

/// Generates generic argument slots for user-specified `args` and
Expand Down
123 changes: 84 additions & 39 deletions compiler/rustc_ast_lowering/src/delegation/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ use hir::def::Res;
use rustc_abi::ExternAbi;
use rustc_ast as ast;
use rustc_ast::*;
use rustc_hir::def::DefKind;
use rustc_hir::{self as hir, FnDeclFlags};
use rustc_middle::ty::Asyncness;
use rustc_span::def_id::DefId;
Expand Down Expand Up @@ -249,20 +250,19 @@ impl<'hir> LoweringContext<'_, 'hir> {
let mut unused_target_expr = false;

let block_id = self.lower_body(|this| {
let &DelegationResolution {
param_info, span, should_generate_block, is_method, ..
} = res;

let &DelegationResolution { param_info, span, is_method, .. } = res;
let ParamInfo { param_count, .. } = param_info;
let arguments_to_map = &res.sig_mapping.arguments_to_map;

let mut parameters: Vec<hir::Param<'_>> = Vec::with_capacity(param_count);
let mut args: Vec<hir::Expr<'_>> = Vec::with_capacity(param_count);
let mut stmts: &[hir::Stmt<'hir>] = &[];
let mut stmts = vec![];

// Consider non-specified target expression as generated,
// as we do not want to emit error when target expression is
// not specified.
unused_target_expr = block.is_some() && (param_count == 0 || !should_generate_block);
unused_target_expr =
block.is_some() && (param_count == 0 || arguments_to_map.is_empty());

for idx in 0..param_count {
let (param, pat_node_id) = this.generate_param(is_method, idx, span);
Expand All @@ -271,41 +271,38 @@ impl<'hir> LoweringContext<'_, 'hir> {
let generate_arg =
|this: &mut Self| this.generate_arg(is_method, idx, param.pat.hir_id, span);

let arg = if let Some(block) = block
&& idx == 0
&& should_generate_block
{
let mut self_resolver = SelfResolver {
ctxt: this,
path_id: delegation.id,
self_param_id: pat_node_id,
};
self_resolver.visit_block(block);
// Target expr needs to lower `self` path.
this.ident_and_label_to_local_id.insert(pat_node_id, param.pat.hir_id.local_id);

// Lower with `HirId::INVALID` as we will use only expr and stmts.
// FIXME(fn_delegation): Alternatives for target expression lowering:
// https://github.com/rust-lang/rfcs/pull/3530#issuecomment-2197170600.
let block = this.lower_block_noalloc(HirId::INVALID, block, false);

stmts = block.stmts;

// The behavior of the delegation's target expression differs from the
// behavior of the usual block, where if there is no final expression
// the `()` is returned. In case of the similar situation in delegation
// (no final expression) we propagate first argument instead of replacing
// it with `()`.
if let Some(&expr) = block.expr { expr } else { generate_arg(this) }
} else {
generate_arg(this)
};
let arg = block
.filter(|_| arguments_to_map.contains(&idx))
.and_then(|block| {
let block = this.lower_block_maybe_more_than_once(
block,
pat_node_id,
param.pat.hir_id.local_id,
delegation.id,
);

stmts.push(block.stmts);

// The behavior of the delegation's target expression differs from the
// behavior of the usual block, where if there is no final expression
// the `()` is returned. In case of the similar situation in delegation
// (no final expression) we propagate first argument instead of replacing
// it with `()`.
block.expr.copied()
})
.unwrap_or_else(|| generate_arg(this));

args.push(arg);
}

let (final_expr, hir_id) =
this.finalize_body_lowering(delegation, stmts, args, res, generics, span);
let (final_expr, hir_id) = this.finalize_body_lowering(
delegation,
this.arena.alloc_from_iter(stmts.into_iter().flatten().copied()),
args,
res,
generics,
span,
);

call_expr_id = hir_id;

Expand All @@ -317,6 +314,48 @@ impl<'hir> LoweringContext<'_, 'hir> {
(block_id, call_expr_id, unused_target_expr)
}

fn lower_block_maybe_more_than_once(
&mut self,
block: &Block,
pat_node_id: NodeId,
param_local_id: hir::ItemLocalId,
delegation_id: NodeId,
) -> hir::Block<'hir> {
let mut self_resolver = SelfResolver {
ctxt: self,
path_id: delegation_id,
self_param_id: pat_node_id,
overwrites: vec![],
};

self_resolver.visit_block(block);

let overwrites = self_resolver.overwrites;

// Target expr needs to lower `self` path.
self.ident_and_label_to_local_id.insert(pat_node_id, param_local_id);

let block = cfg_select! {
debug_assertions => {
crate::re_lowering::ReloweringChecker::allow_relowering(self, |this| {
this.lower_block_noalloc(HirId::INVALID, block, false)
})
},
_ => self.lower_block_noalloc(HirId::INVALID, block, false)
};

// Remove node ids for which we overwrote resolution to generated param
// before block lowering as block can be relowered. We need to do it because
// check in `SelfResolver` uses `get_partial_res` to decide whether to overwrite
// resolution, and if it is already overwritten from previous block lowering this
// check will not pass.
for id in overwrites {
self.partial_res_overrides.remove(&id);
Comment thread
aerooneqq marked this conversation as resolved.
}

block
}

fn finalize_body_lowering(
&mut self,
delegation: &Delegation,
Expand Down Expand Up @@ -392,8 +431,12 @@ impl<'hir> LoweringContext<'_, 'hir> {
let args = self.arena.alloc_from_iter(args);
let call = self.mk_expr(hir::ExprKind::Call(callee_path, args), span);

let expr = if let Some((parent, of_trait)) = res.output_self_mapping {
let res = Res::SelfTyAlias { alias_to: parent.to_def_id(), is_trait_impl: of_trait };
let expr = if res.sig_mapping.map_return {
let res = Res::SelfTyAlias {
alias_to: res.parent.to_def_id(),
is_trait_impl: self.tcx.def_kind(res.parent) == DefKind::Impl { of_trait: true },
};

let ident = Ident::new(kw::SelfUpper, span);
let path = self.create_resolved_path(res, ident, span);

Expand Down Expand Up @@ -538,6 +581,7 @@ struct SelfResolver<'a, 'b, 'hir> {
ctxt: &'a mut LoweringContext<'b, 'hir>,
path_id: NodeId,
self_param_id: NodeId,
overwrites: Vec<NodeId>,
}

impl SelfResolver<'_, '_, '_> {
Expand All @@ -546,6 +590,7 @@ impl SelfResolver<'_, '_, '_> {
&& let Some(Res::Local(sig_id)) = res.full_res()
&& sig_id == self.path_id
{
self.overwrites.push(id);
self.ctxt.partial_res_overrides.insert(id, self.self_param_id);
}
}
Expand Down
Loading
Loading