1
Fork 0

Implement #[define_opaque] attribute for functions.

This commit is contained in:
Oli Scherer 2024-07-26 10:04:02 +00:00 committed by Oli Scherer
parent 2c6a12ec44
commit cb4751d4b8
653 changed files with 2911 additions and 2580 deletions

View file

@ -3,10 +3,9 @@ use rustc_ast::ptr::P;
use rustc_ast::visit::AssocCtxt;
use rustc_ast::*;
use rustc_errors::ErrorGuaranteed;
use rustc_hir as hir;
use rustc_hir::PredicateOrigin;
use rustc_hir::def::{DefKind, Res};
use rustc_hir::def_id::{CRATE_DEF_ID, LocalDefId};
use rustc_hir::{self as hir, HirId, PredicateOrigin};
use rustc_index::{IndexSlice, IndexVec};
use rustc_middle::span_bug;
use rustc_middle::ty::{ResolverAstLowering, TyCtxt};
@ -209,6 +208,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
generics,
body,
contract,
define_opaque,
..
}) => {
self.with_new_scopes(*fn_sig_span, |this| {
@ -237,6 +237,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
header: this.lower_fn_header(*header, hir::Safety::Safe, attrs),
span: this.lower_span(*fn_sig_span),
};
this.lower_define_opaque(hir_id, &define_opaque);
hir::ItemKind::Fn { sig, generics, body: body_id, has_body: body.is_some() }
})
}
@ -779,7 +780,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
);
(generics, kind, expr.is_some())
}
AssocItemKind::Fn(box Fn { sig, generics, body: None, .. }) => {
AssocItemKind::Fn(box Fn { sig, generics, body: None, define_opaque, .. }) => {
// FIXME(contracts): Deny contract here since it won't apply to
// any impl method or callees.
let names = self.lower_fn_params_to_names(&sig.decl);
@ -791,9 +792,22 @@ impl<'hir> LoweringContext<'_, 'hir> {
sig.header.coroutine_kind,
attrs,
);
if define_opaque.is_some() {
self.dcx().span_err(
i.span,
"only trait methods with default bodies can define opaque types",
);
}
(generics, hir::TraitItemKind::Fn(sig, hir::TraitFn::Required(names)), false)
}
AssocItemKind::Fn(box Fn { sig, generics, body: Some(body), contract, .. }) => {
AssocItemKind::Fn(box Fn {
sig,
generics,
body: Some(body),
contract,
define_opaque,
..
}) => {
let body_id = self.lower_maybe_coroutine_body(
sig.span,
i.span,
@ -812,6 +826,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
sig.header.coroutine_kind,
attrs,
);
self.lower_define_opaque(hir_id, &define_opaque);
(generics, hir::TraitItemKind::Fn(sig, hir::TraitFn::Provided(body_id)), true)
}
AssocItemKind::Type(box TyAlias { generics, where_clauses, bounds, ty, .. }) => {
@ -911,7 +926,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
hir::ImplItemKind::Const(ty, body)
},
),
AssocItemKind::Fn(box Fn { sig, generics, body, contract, .. }) => {
AssocItemKind::Fn(box Fn { sig, generics, body, contract, define_opaque, .. }) => {
let body_id = self.lower_maybe_coroutine_body(
sig.span,
i.span,
@ -930,6 +945,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
sig.header.coroutine_kind,
attrs,
);
self.lower_define_opaque(hir_id, &define_opaque);
(generics, hir::ImplItemKind::Fn(sig, body_id))
}
@ -1657,6 +1673,31 @@ impl<'hir> LoweringContext<'_, 'hir> {
(lowered_generics, res)
}
pub(super) fn lower_define_opaque(
&mut self,
hir_id: HirId,
define_opaque: &Option<ThinVec<(NodeId, Path)>>,
) {
assert_eq!(self.define_opaque, None);
assert!(hir_id.is_owner());
let Some(define_opaque) = define_opaque.as_ref() else {
return;
};
let define_opaque = define_opaque
.iter()
// TODO: error reporting for non-local items being mentioned and tests that go through these code paths
.map(|(id, _path)| {
self.resolver
.get_partial_res(*id)
.unwrap()
.expect_full_res()
.def_id()
.expect_local()
});
let define_opaque = self.arena.alloc_from_iter(define_opaque);
self.define_opaque = Some(define_opaque);
}
pub(super) fn lower_generic_bound_predicate(
&mut self,
ident: Ident,

View file

@ -35,6 +35,7 @@
#![doc(rust_logo)]
#![feature(assert_matches)]
#![feature(box_patterns)]
#![feature(exact_size_is_empty)]
#![feature(if_let_guard)]
#![feature(let_chains)]
#![feature(rustdoc_internals)]
@ -97,6 +98,8 @@ struct LoweringContext<'a, 'hir> {
/// Bodies inside the owner being lowered.
bodies: Vec<(hir::ItemLocalId, &'hir hir::Body<'hir>)>,
/// `#[define_opaque]` attributes
define_opaque: Option<&'hir [LocalDefId]>,
/// Attributes inside the owner being lowered.
attrs: SortedMap<hir::ItemLocalId, &'hir [hir::Attribute]>,
/// Collect items that were created by lowering the current owner.
@ -154,6 +157,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
// HirId handling.
bodies: Vec::new(),
define_opaque: None,
attrs: SortedMap::default(),
children: Vec::default(),
contract_ensures: None,
@ -546,6 +550,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
let current_attrs = std::mem::take(&mut self.attrs);
let current_bodies = std::mem::take(&mut self.bodies);
let current_define_opaque = std::mem::take(&mut self.define_opaque);
let current_ident_and_label_to_local_id =
std::mem::take(&mut self.ident_and_label_to_local_id);
@ -579,6 +584,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
self.attrs = current_attrs;
self.bodies = current_bodies;
self.define_opaque = current_define_opaque;
self.ident_and_label_to_local_id = current_ident_and_label_to_local_id;
#[cfg(debug_assertions)]
@ -598,6 +604,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
fn make_owner_info(&mut self, node: hir::OwnerNode<'hir>) -> &'hir hir::OwnerInfo<'hir> {
let attrs = std::mem::take(&mut self.attrs);
let mut bodies = std::mem::take(&mut self.bodies);
let define_opaque = std::mem::take(&mut self.define_opaque);
let trait_map = std::mem::take(&mut self.trait_map);
#[cfg(debug_assertions)]
@ -617,7 +624,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
let num_nodes = self.item_local_id_counter.as_usize();
let (nodes, parenting) = index::index_hir(self.tcx, node, &bodies, num_nodes);
let nodes = hir::OwnerNodes { opt_hash_including_bodies, nodes, bodies };
let attrs = hir::AttributeMap { map: attrs, opt_hash: attrs_hash };
let attrs = hir::AttributeMap { map: attrs, opt_hash: attrs_hash, define_opaque };
self.arena.alloc(hir::OwnerInfo { nodes, parenting, attrs, trait_map })
}