Skip to content

Commit

Permalink
Delegation: partial generics support
Browse files Browse the repository at this point in the history
  • Loading branch information
Bryanskiy committed May 29, 2024
1 parent b582f80 commit 7634ac5
Show file tree
Hide file tree
Showing 27 changed files with 1,073 additions and 253 deletions.
2 changes: 1 addition & 1 deletion compiler/rustc_ast_lowering/src/delegation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
//! HIR ty lowering.
//!
//! Similarly generics, predicates and header are set to the "default" values.
//! In case of discrepancy with callee function the `NotSupportedDelegation` error will
//! In case of discrepancy with callee function the `UnsupportedDelegation` error will
//! also be emitted during HIR ty lowering.

use crate::{ImplTraitPosition, ResolverAstLoweringExt};
Expand Down
4 changes: 0 additions & 4 deletions compiler/rustc_hir_analysis/messages.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -309,10 +309,6 @@ hir_analysis_must_implement_not_function_span_note = required by this annotation
hir_analysis_must_implement_one_of_attribute = the `#[rustc_must_implement_one_of]` attribute must be used with at least 2 args
hir_analysis_not_supported_delegation =
{$descr} is not supported yet
.label = callee defined here
hir_analysis_only_current_traits_adt = `{$name}` is not defined in the current crate
hir_analysis_only_current_traits_arbitrary = only traits defined in the current crate can be implemented for arbitrary types
Expand Down
6 changes: 6 additions & 0 deletions compiler/rustc_hir_analysis/src/collect/generics_of.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,12 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics {
};
}

if tcx.hir().opt_delegation_sig_id(def_id).is_some()
&& let Some(generics) = &tcx.lower_delegation_ty(def_id).generics
{
return generics.clone();
}

let hir_id = tcx.local_def_id_to_hir_id(def_id);

let node = tcx.hir_node(hir_id);
Expand Down
6 changes: 6 additions & 0 deletions compiler/rustc_hir_analysis/src/collect/predicates_of.rs
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,12 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen
None => {}
}

if tcx.hir().opt_delegation_sig_id(def_id).is_some()
&& let Some(predicates) = tcx.lower_delegation_ty(def_id).predicates
{
return predicates;
}

let hir_id = tcx.local_def_id_to_hir_id(def_id);
let node = tcx.hir_node(hir_id);

Expand Down
10 changes: 0 additions & 10 deletions compiler/rustc_hir_analysis/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1569,16 +1569,6 @@ pub enum RefOfMutStaticSugg {
},
}

#[derive(Diagnostic)]
#[diag(hir_analysis_not_supported_delegation)]
pub struct NotSupportedDelegation<'a> {
#[primary_span]
pub span: Span,
pub descr: &'a str,
#[label]
pub callee_span: Span,
}

#[derive(Diagnostic)]
#[diag(hir_analysis_method_should_return_future)]
pub struct MethodShouldReturnFuture {
Expand Down
95 changes: 5 additions & 90 deletions compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1939,94 +1939,11 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
self.lower_ty_common(hir_ty, false, true)
}

fn check_delegation_constraints(&self, sig_id: DefId, span: Span, emit: bool) -> bool {
let mut error_occured = false;
let sig_span = self.tcx().def_span(sig_id);
let mut try_emit = |descr| {
if emit {
self.tcx().dcx().emit_err(crate::errors::NotSupportedDelegation {
span,
descr,
callee_span: sig_span,
});
}
error_occured = true;
};

if let Some(node) = self.tcx().hir().get_if_local(sig_id)
&& let Some(decl) = node.fn_decl()
&& let hir::FnRetTy::Return(ty) = decl.output
&& let hir::TyKind::InferDelegation(_, _) = ty.kind
{
try_emit("recursive delegation");
}

let sig_generics = self.tcx().generics_of(sig_id);
let parent = self.tcx().parent(self.item_def_id());
let parent_generics = self.tcx().generics_of(parent);

let parent_is_trait = (self.tcx().def_kind(parent) == DefKind::Trait) as usize;
let sig_has_self = sig_generics.has_self as usize;

if sig_generics.count() > sig_has_self || parent_generics.count() > parent_is_trait {
try_emit("delegation with early bound generics");
}

// There is no way to instantiate `Self` param for caller if
// 1. callee is a trait method
// 2. delegation item isn't an associative item
if let DefKind::AssocFn = self.tcx().def_kind(sig_id)
&& let DefKind::Fn = self.tcx().def_kind(self.item_def_id())
&& self.tcx().associated_item(sig_id).container
== ty::AssocItemContainer::TraitContainer
{
try_emit("delegation to a trait method from a free function");
}

error_occured
}

fn lower_delegation_ty(
&self,
sig_id: DefId,
idx: hir::InferDelegationKind,
span: Span,
) -> Ty<'tcx> {
if self.check_delegation_constraints(sig_id, span, idx == hir::InferDelegationKind::Output)
{
let e = self.tcx().dcx().span_delayed_bug(span, "not supported delegation case");
self.set_tainted_by_errors(e);
return Ty::new_error(self.tcx(), e);
};
let sig = self.tcx().fn_sig(sig_id);
let sig_generics = self.tcx().generics_of(sig_id);

let parent = self.tcx().parent(self.item_def_id());
let parent_def_kind = self.tcx().def_kind(parent);

let sig = if let DefKind::Impl { .. } = parent_def_kind
&& sig_generics.has_self
{
// Generic params can't be here except the trait self type.
// They are not supported yet.
assert_eq!(sig_generics.count(), 1);
assert_eq!(self.tcx().generics_of(parent).count(), 0);

let self_ty = self.tcx().type_of(parent).instantiate_identity();
let generic_self_ty = ty::GenericArg::from(self_ty);
let args = self.tcx().mk_args_from_iter(std::iter::once(generic_self_ty));
sig.instantiate(self.tcx(), args)
} else {
sig.instantiate_identity()
};

// Bound vars are also inherited from `sig_id`.
// They will be rebound later in `lower_fn_ty`.
let sig = sig.skip_binder();

fn lower_delegation_ty(&self, idx: hir::InferDelegationKind) -> Ty<'tcx> {
let delegation_res = self.tcx().lower_delegation_ty(self.item_def_id().expect_local());
match idx {
hir::InferDelegationKind::Input(id) => sig.inputs()[id],
hir::InferDelegationKind::Output => sig.output(),
hir::InferDelegationKind::Input(idx) => delegation_res.inputs[idx],
hir::InferDelegationKind::Output => delegation_res.output,
}
}

Expand All @@ -2043,9 +1960,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
let tcx = self.tcx();

let result_ty = match &hir_ty.kind {
hir::TyKind::InferDelegation(sig_id, idx) => {
self.lower_delegation_ty(*sig_id, *idx, hir_ty.span)
}
hir::TyKind::InferDelegation(_, idx) => self.lower_delegation_ty(*idx),
hir::TyKind::Slice(ty) => Ty::new_slice(tcx, self.lower_ty(ty)),
hir::TyKind::Ptr(mt) => Ty::new_ptr(tcx, self.lower_ty(mt.ty), mt.mutbl),
hir::TyKind::Ref(region, mt) => {
Expand Down
4 changes: 4 additions & 0 deletions compiler/rustc_hir_typeck/messages.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,10 @@ hir_typeck_no_associated_item = no {$item_kind} named `{$item_name}` found for {
*[other] {" "}in the current scope
}
hir_typeck_not_supported_delegation =
{$descr}
.label = callee defined here
hir_typeck_note_caller_chooses_ty_for_ty_param = the caller chooses a type for `{$ty_param_name}` which can be different from `{$found_ty}`
hir_typeck_note_edition_guide = for more on editions, read https://doc.rust-lang.org/edition-guide
Expand Down
Loading

0 comments on commit 7634ac5

Please sign in to comment.