Auto merge of #128440 - oli-obk:defines, r=lcnr
Add `#[define_opaques]` attribute and require it for all type-alias-impl-trait sites that register a hidden type Instead of relying on the signature of items to decide whether they are constraining an opaque type, the opaque types that the item constrains must be explicitly listed. A previous version of this PR used an actual attribute, but had to keep the resolved `DefId`s in a side table. Now we just lower to fields in the AST that have no surface syntax, instead a builtin attribute macro fills in those fields where applicable. Note that for convenience referencing opaque types in associated types from associated methods on the same impl will not require an attribute. If that causes problems `#[defines()]` can be used to overwrite the default of searching for opaques in the signature. One wart of this design is that closures and static items do not have generics. So since I stored the opaques in the generics of functions, consts and methods, I would need to add a custom field to closures and statics to track this information. During a T-types discussion we decided to just not do this for now. fixes #131298
This commit is contained in:
commit
6650252439
666 changed files with 3025 additions and 2582 deletions
|
@ -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,35 @@ 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().filter_map(|(id, path)| {
|
||||
let res = self.resolver.get_partial_res(*id).unwrap();
|
||||
let Some(did) = res.expect_full_res().opt_def_id() else {
|
||||
self.dcx().span_delayed_bug(path.span, "should have errored in resolve");
|
||||
return None;
|
||||
};
|
||||
let Some(did) = did.as_local() else {
|
||||
self.dcx().span_err(
|
||||
path.span,
|
||||
"only opaque types defined in the local crate can be defined",
|
||||
);
|
||||
return None;
|
||||
};
|
||||
Some((self.lower_span(path.span), did))
|
||||
});
|
||||
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,
|
||||
|
|
|
@ -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)]
|
||||
|
@ -98,6 +99,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 [(Span, LocalDefId)]>,
|
||||
/// Attributes inside the owner being lowered.
|
||||
attrs: SortedMap<hir::ItemLocalId, &'hir [hir::Attribute]>,
|
||||
/// Collect items that were created by lowering the current owner.
|
||||
|
@ -155,6 +158,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
|
||||
// HirId handling.
|
||||
bodies: Vec::new(),
|
||||
define_opaque: None,
|
||||
attrs: SortedMap::default(),
|
||||
children: Vec::default(),
|
||||
contract_ensures: None,
|
||||
|
@ -547,6 +551,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);
|
||||
|
||||
|
@ -580,6 +585,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)]
|
||||
|
@ -599,6 +605,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)]
|
||||
|
@ -618,7 +625,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 })
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue