summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_ast_lowering/src
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-30 03:59:35 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-30 03:59:35 +0000
commitd1b2d29528b7794b41e66fc2136e395a02f8529b (patch)
treea4a17504b260206dec3cf55b2dca82929a348ac2 /compiler/rustc_ast_lowering/src
parentReleasing progress-linux version 1.72.1+dfsg1-1~progress7.99u1. (diff)
downloadrustc-d1b2d29528b7794b41e66fc2136e395a02f8529b.tar.xz
rustc-d1b2d29528b7794b41e66fc2136e395a02f8529b.zip
Merging upstream version 1.73.0+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'compiler/rustc_ast_lowering/src')
-rw-r--r--compiler/rustc_ast_lowering/src/asm.rs8
-rw-r--r--compiler/rustc_ast_lowering/src/errors.rs17
-rw-r--r--compiler/rustc_ast_lowering/src/expr.rs18
-rw-r--r--compiler/rustc_ast_lowering/src/item.rs172
-rw-r--r--compiler/rustc_ast_lowering/src/lib.rs692
-rw-r--r--compiler/rustc_ast_lowering/src/lifetime_collector.rs25
-rw-r--r--compiler/rustc_ast_lowering/src/pat.rs3
-rw-r--r--compiler/rustc_ast_lowering/src/path.rs13
8 files changed, 442 insertions, 506 deletions
diff --git a/compiler/rustc_ast_lowering/src/asm.rs b/compiler/rustc_ast_lowering/src/asm.rs
index d350498bc..a1e626996 100644
--- a/compiler/rustc_ast_lowering/src/asm.rs
+++ b/compiler/rustc_ast_lowering/src/asm.rs
@@ -207,6 +207,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
&sym.path,
ParamMode::Optional,
&ImplTraitContext::Disallowed(ImplTraitPosition::Path),
+ None,
);
hir::InlineAsmOperand::SymStatic { path, def_id }
} else {
@@ -352,7 +353,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
let idx2 = *o.get();
let (ref op2, op_sp2) = operands[idx2];
- let Some(asm::InlineAsmRegOrRegClass::Reg(reg2)) = op2.reg() else {
+ let Some(asm::InlineAsmRegOrRegClass::Reg(reg2)) = op2.reg()
+ else {
unreachable!();
};
@@ -368,7 +370,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
assert!(!*late);
let out_op_sp = if input { op_sp2 } else { op_sp };
Some(out_op_sp)
- },
+ }
_ => None,
};
@@ -377,7 +379,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
op_span2: op_sp2,
reg1_name: reg.name(),
reg2_name: reg2.name(),
- in_out
+ in_out,
});
}
Entry::Vacant(v) => {
diff --git a/compiler/rustc_ast_lowering/src/errors.rs b/compiler/rustc_ast_lowering/src/errors.rs
index 72dc52a63..a63bd4f8a 100644
--- a/compiler/rustc_ast_lowering/src/errors.rs
+++ b/compiler/rustc_ast_lowering/src/errors.rs
@@ -31,9 +31,26 @@ pub struct InvalidAbi {
pub abi: Symbol,
pub command: String,
#[subdiagnostic]
+ pub explain: Option<InvalidAbiReason>,
+ #[subdiagnostic]
pub suggestion: Option<InvalidAbiSuggestion>,
}
+pub struct InvalidAbiReason(pub &'static str);
+
+impl rustc_errors::AddToDiagnostic for InvalidAbiReason {
+ fn add_to_diagnostic_with<F>(self, diag: &mut rustc_errors::Diagnostic, _: F)
+ where
+ F: Fn(
+ &mut rustc_errors::Diagnostic,
+ rustc_errors::SubdiagnosticMessage,
+ ) -> rustc_errors::SubdiagnosticMessage,
+ {
+ #[allow(rustc::untranslatable_diagnostic)]
+ diag.note(self.0);
+ }
+}
+
#[derive(Subdiagnostic)]
#[suggestion(
ast_lowering_invalid_abi_suggestion,
diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs
index dcaaaafed..7408b4fb0 100644
--- a/compiler/rustc_ast_lowering/src/expr.rs
+++ b/compiler/rustc_ast_lowering/src/expr.rs
@@ -100,6 +100,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
ParamMode::Optional,
ParenthesizedGenericArgs::Err,
&ImplTraitContext::Disallowed(ImplTraitPosition::Path),
+ None,
));
let receiver = self.lower_expr(receiver);
let args =
@@ -240,8 +241,8 @@ impl<'hir> LoweringContext<'_, 'hir> {
ExprKind::Field(el, ident) => {
hir::ExprKind::Field(self.lower_expr(el), self.lower_ident(*ident))
}
- ExprKind::Index(el, er) => {
- hir::ExprKind::Index(self.lower_expr(el), self.lower_expr(er))
+ ExprKind::Index(el, er, brackets_span) => {
+ hir::ExprKind::Index(self.lower_expr(el), self.lower_expr(er), *brackets_span)
}
ExprKind::Range(Some(e1), Some(e2), RangeLimits::Closed) => {
self.lower_expr_range_closed(e.span, e1, e2)
@@ -260,6 +261,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
path,
ParamMode::Optional,
&ImplTraitContext::Disallowed(ImplTraitPosition::Path),
+ None,
);
hir::ExprKind::Path(qpath)
}
@@ -286,7 +288,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
ExprKind::OffsetOf(container, fields) => hir::ExprKind::OffsetOf(
self.lower_ty(
container,
- &mut ImplTraitContext::Disallowed(ImplTraitPosition::OffsetOf),
+ &ImplTraitContext::Disallowed(ImplTraitPosition::OffsetOf),
),
self.arena.alloc_from_iter(fields.iter().map(|&ident| self.lower_ident(ident))),
),
@@ -307,6 +309,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
&se.path,
ParamMode::Optional,
&ImplTraitContext::Disallowed(ImplTraitPosition::Path),
+ None,
)),
self.arena
.alloc_from_iter(se.fields.iter().map(|x| self.lower_expr_field(x))),
@@ -657,14 +660,14 @@ impl<'hir> LoweringContext<'_, 'hir> {
}
/// Forwards a possible `#[track_caller]` annotation from `outer_hir_id` to
- /// `inner_hir_id` in case the `closure_track_caller` feature is enabled.
+ /// `inner_hir_id` in case the `async_fn_track_caller` feature is enabled.
pub(super) fn maybe_forward_track_caller(
&mut self,
span: Span,
outer_hir_id: hir::HirId,
inner_hir_id: hir::HirId,
) {
- if self.tcx.features().closure_track_caller
+ if self.tcx.features().async_fn_track_caller
&& let Some(attrs) = self.attrs.get(&outer_hir_id.local_id)
&& attrs.into_iter().any(|attr| attr.has_name(sym::track_caller))
{
@@ -1179,6 +1182,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
path,
ParamMode::Optional,
&ImplTraitContext::Disallowed(ImplTraitPosition::Path),
+ None,
);
// Destructure like a tuple struct.
let tuple_struct_pat = hir::PatKind::TupleStruct(
@@ -1198,6 +1202,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
path,
ParamMode::Optional,
&ImplTraitContext::Disallowed(ImplTraitPosition::Path),
+ None,
);
// Destructure like a unit struct.
let unit_struct_pat = hir::PatKind::Path(qpath);
@@ -1222,6 +1227,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
&se.path,
ParamMode::Optional,
&ImplTraitContext::Disallowed(ImplTraitPosition::Path),
+ None,
);
let fields_omitted = match &se.rest {
StructRest::Base(e) => {
@@ -1642,7 +1648,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
hir::ExprKind::Match(
scrutinee,
arena_vec![self; break_arm, continue_arm],
- hir::MatchSource::TryDesugar,
+ hir::MatchSource::TryDesugar(scrutinee.hir_id),
)
}
diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs
index ab68436c0..a59c83de0 100644
--- a/compiler/rustc_ast_lowering/src/item.rs
+++ b/compiler/rustc_ast_lowering/src/item.rs
@@ -1,4 +1,4 @@
-use super::errors::{InvalidAbi, InvalidAbiSuggestion, MisplacedRelaxTraitBound};
+use super::errors::{InvalidAbi, InvalidAbiReason, InvalidAbiSuggestion, MisplacedRelaxTraitBound};
use super::ResolverAstLoweringExt;
use super::{AstOwner, ImplTraitContext, ImplTraitPosition};
use super::{FnDeclKind, LoweringContext, ParamMode};
@@ -56,6 +56,11 @@ impl<'a, 'hir> ItemLowerer<'a, 'hir> {
owner: NodeId,
f: impl FnOnce(&mut LoweringContext<'_, 'hir>) -> hir::OwnerNode<'hir>,
) {
+ let allow_gen_future = Some(if self.tcx.features().async_fn_track_caller {
+ [sym::gen_future, sym::closure_track_caller][..].into()
+ } else {
+ [sym::gen_future][..].into()
+ });
let mut lctx = LoweringContext {
// Pseudo-globals.
tcx: self.tcx,
@@ -83,8 +88,9 @@ impl<'a, 'hir> ItemLowerer<'a, 'hir> {
impl_trait_defs: Vec::new(),
impl_trait_bounds: Vec::new(),
allow_try_trait: Some([sym::try_trait_v2, sym::yeet_desugar_details][..].into()),
- allow_gen_future: Some([sym::gen_future, sym::closure_track_caller][..].into()),
+ allow_gen_future,
generics_def_id_map: Default::default(),
+ host_param_id: None,
};
lctx.with_hir_id_owner(owner, |lctx| f(lctx));
@@ -139,8 +145,24 @@ impl<'a, 'hir> ItemLowerer<'a, 'hir> {
// This is used to track which lifetimes have already been defined,
// and which need to be replicated when lowering an async fn.
- if let hir::ItemKind::Impl(impl_) = parent_hir.node().expect_item().kind {
- lctx.is_in_trait_impl = impl_.of_trait.is_some();
+ match parent_hir.node().expect_item().kind {
+ hir::ItemKind::Impl(impl_) => {
+ lctx.is_in_trait_impl = impl_.of_trait.is_some();
+ }
+ hir::ItemKind::Trait(_, _, generics, _, _) if lctx.tcx.features().effects => {
+ lctx.host_param_id = generics
+ .params
+ .iter()
+ .find(|param| {
+ parent_hir
+ .attrs
+ .get(param.hir_id.local_id)
+ .iter()
+ .any(|attr| attr.has_name(sym::rustc_host))
+ })
+ .map(|param| param.def_id);
+ }
+ _ => {}
}
match ctxt {
@@ -231,9 +253,15 @@ impl<'hir> LoweringContext<'_, 'hir> {
let (ty, body_id) = self.lower_const_item(t, span, e.as_deref());
hir::ItemKind::Static(ty, *m, body_id)
}
- ItemKind::Const(box ast::ConstItem { ty, expr, .. }) => {
- let (ty, body_id) = self.lower_const_item(ty, span, expr.as_deref());
- hir::ItemKind::Const(ty, body_id)
+ ItemKind::Const(box ast::ConstItem { generics, ty, expr, .. }) => {
+ let (generics, (ty, body_id)) = self.lower_generics(
+ generics,
+ Const::No,
+ id,
+ &ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
+ |this| this.lower_const_item(ty, span, expr.as_deref()),
+ );
+ hir::ItemKind::Const(ty, generics, body_id)
}
ItemKind::Fn(box Fn {
sig: FnSig { decl, header, span: fn_sig_span },
@@ -378,6 +406,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
self.lower_generics(ast_generics, *constness, id, &itctx, |this| {
let trait_ref = trait_ref.as_ref().map(|trait_ref| {
this.lower_trait_ref(
+ *constness,
trait_ref,
&ImplTraitContext::Disallowed(ImplTraitPosition::Trait),
)
@@ -408,7 +437,6 @@ impl<'hir> LoweringContext<'_, 'hir> {
polarity,
defaultness,
defaultness_span,
- constness: self.lower_constness(*constness),
generics,
of_trait: trait_ref,
self_ty: lowered_ty,
@@ -551,17 +579,6 @@ impl<'hir> LoweringContext<'_, 'hir> {
for &(ref use_tree, id) in trees {
let new_hir_id = self.local_def_id(id);
- let mut prefix = prefix.clone();
-
- // Give the segments new node-ids since they are being cloned.
- for seg in &mut prefix.segments {
- // Give the cloned segment the same resolution information
- // as the old one (this is needed for stability checking).
- let new_id = self.next_node_id();
- self.resolver.clone_res(seg.id, new_id);
- seg.id = new_id;
- }
-
// Each `use` import is an item and thus are owners of the
// names in the path. Up to this point the nested import is
// the current owner, since we want each desugared import to
@@ -570,6 +587,9 @@ impl<'hir> LoweringContext<'_, 'hir> {
self.with_hir_id_owner(id, |this| {
let mut ident = *ident;
+ // `prefix` is lowered multiple times, but in different HIR owners.
+ // So each segment gets renewed `HirId` with the same
+ // `ItemLocalId` and the new owner. (See `lower_node_id`)
let kind =
this.lower_use_tree(use_tree, &prefix, id, vis_span, &mut ident, attrs);
if let Some(attrs) = attrs {
@@ -723,11 +743,23 @@ impl<'hir> LoweringContext<'_, 'hir> {
let trait_item_def_id = hir_id.expect_owner();
let (generics, kind, has_default) = match &i.kind {
- AssocItemKind::Const(box ConstItem { ty, expr, .. }) => {
- let ty =
- self.lower_ty(ty, &ImplTraitContext::Disallowed(ImplTraitPosition::ConstTy));
- let body = expr.as_ref().map(|x| self.lower_const_body(i.span, Some(x)));
- (hir::Generics::empty(), hir::TraitItemKind::Const(ty, body), body.is_some())
+ AssocItemKind::Const(box ConstItem { generics, ty, expr, .. }) => {
+ let (generics, kind) = self.lower_generics(
+ &generics,
+ Const::No,
+ i.id,
+ &ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
+ |this| {
+ let ty = this.lower_ty(
+ ty,
+ &ImplTraitContext::Disallowed(ImplTraitPosition::ConstTy),
+ );
+ let body = expr.as_ref().map(|x| this.lower_const_body(i.span, Some(x)));
+
+ hir::TraitItemKind::Const(ty, body)
+ },
+ );
+ (generics, kind, expr.is_some())
}
AssocItemKind::Fn(box Fn { sig, generics, body: None, .. }) => {
let asyncness = sig.header.asyncness;
@@ -825,14 +857,19 @@ impl<'hir> LoweringContext<'_, 'hir> {
self.lower_attrs(hir_id, &i.attrs);
let (generics, kind) = match &i.kind {
- AssocItemKind::Const(box ConstItem { ty, expr, .. }) => {
- let ty =
- self.lower_ty(ty, &ImplTraitContext::Disallowed(ImplTraitPosition::ConstTy));
- (
- hir::Generics::empty(),
- hir::ImplItemKind::Const(ty, self.lower_const_body(i.span, expr.as_deref())),
- )
- }
+ AssocItemKind::Const(box ConstItem { generics, ty, expr, .. }) => self.lower_generics(
+ &generics,
+ Const::No,
+ i.id,
+ &ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
+ |this| {
+ let ty = this
+ .lower_ty(ty, &ImplTraitContext::Disallowed(ImplTraitPosition::ConstTy));
+ let body = this.lower_const_body(i.span, expr.as_deref());
+
+ hir::ImplItemKind::Const(ty, body)
+ },
+ ),
AssocItemKind::Fn(box Fn { sig, generics, body, .. }) => {
self.current_item = Some(i.span);
let asyncness = sig.header.asyncness;
@@ -1234,8 +1271,8 @@ impl<'hir> LoweringContext<'_, 'hir> {
}
pub(super) fn lower_abi(&mut self, abi: StrLit) -> abi::Abi {
- abi::lookup(abi.symbol_unescaped.as_str()).unwrap_or_else(|| {
- self.error_on_invalid_abi(abi);
+ abi::lookup(abi.symbol_unescaped.as_str()).unwrap_or_else(|err| {
+ self.error_on_invalid_abi(abi, err);
abi::Abi::Rust
})
}
@@ -1248,7 +1285,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
}
}
- fn error_on_invalid_abi(&self, abi: StrLit) {
+ fn error_on_invalid_abi(&self, abi: StrLit, err: abi::AbiUnsupported) {
let abi_names = abi::enabled_names(self.tcx.features(), abi.span)
.iter()
.map(|s| Symbol::intern(s))
@@ -1257,6 +1294,10 @@ impl<'hir> LoweringContext<'_, 'hir> {
self.tcx.sess.emit_err(InvalidAbi {
abi: abi.symbol_unescaped,
span: abi.span,
+ explain: match err {
+ abi::AbiUnsupported::Reason { explain } => Some(InvalidAbiReason(explain)),
+ _ => None,
+ },
suggestion: suggested_name.map(|suggested_name| InvalidAbiSuggestion {
span: abi.span,
suggestion: format!("\"{suggested_name}\""),
@@ -1343,6 +1384,29 @@ impl<'hir> LoweringContext<'_, 'hir> {
}
}
+ // Desugar `~const` bound in generics into an additional `const host: bool` param
+ // if the effects feature is enabled. This needs to be done before we lower where
+ // clauses since where clauses need to bind to the DefId of the host param
+ let host_param_parts = if let Const::Yes(span) = constness && self.tcx.features().effects {
+ if let Some(param) = generics.params.iter().find(|x| {
+ x.attrs.iter().any(|x| x.has_name(sym::rustc_host))
+ }) {
+ // user has manually specified a `rustc_host` param, in this case, we set
+ // the param id so that lowering logic can use that. But we don't create
+ // another host param, so this gives `None`.
+ self.host_param_id = Some(self.local_def_id(param.id));
+ None
+ } else {
+ let param_node_id = self.next_node_id();
+ let hir_id = self.next_id();
+ let def_id = self.create_def(self.local_def_id(parent_node_id), param_node_id, DefPathData::TypeNs(sym::host), span);
+ self.host_param_id = Some(def_id);
+ Some((span, hir_id, def_id))
+ }
+ } else {
+ None
+ };
+
let mut predicates: SmallVec<[hir::WherePredicate<'hir>; 4]> = SmallVec::new();
predicates.extend(generics.params.iter().filter_map(|param| {
self.lower_generic_bound_predicate(
@@ -1390,22 +1454,11 @@ impl<'hir> LoweringContext<'_, 'hir> {
let impl_trait_bounds = std::mem::take(&mut self.impl_trait_bounds);
predicates.extend(impl_trait_bounds.into_iter());
- // Desugar `~const` bound in generics into an additional `const host: bool` param
- // if the effects feature is enabled.
- if let Const::Yes(span) = constness && self.tcx.features().effects
- // Do not add host param if it already has it (manually specified)
- && !params.iter().any(|x| {
- self.attrs.get(&x.hir_id.local_id).map_or(false, |attrs| {
- attrs.iter().any(|x| x.has_name(sym::rustc_host))
- })
- })
- {
- let param_node_id = self.next_node_id();
+ if let Some((span, hir_id, def_id)) = host_param_parts {
let const_node_id = self.next_node_id();
- let def_id = self.create_def(self.local_def_id(parent_node_id), param_node_id, DefPathData::TypeNs(sym::host), span);
- let anon_const: LocalDefId = self.create_def(def_id, const_node_id, DefPathData::AnonConst, span);
+ let anon_const: LocalDefId =
+ self.create_def(def_id, const_node_id, DefPathData::AnonConst, span);
- let hir_id = self.next_id();
let const_id = self.next_id();
let const_expr_id = self.next_id();
let bool_id = self.next_id();
@@ -1415,14 +1468,15 @@ impl<'hir> LoweringContext<'_, 'hir> {
let attr_id = self.tcx.sess.parse_sess.attr_id_generator.mk_attr_id();
- let attrs = self.arena.alloc_from_iter([
- Attribute {
- kind: AttrKind::Normal(P(NormalAttr::from_ident(Ident::new(sym::rustc_host, span)))),
+ let attrs = self.arena.alloc_from_iter([Attribute {
+ kind: AttrKind::Normal(P(NormalAttr::from_ident(Ident::new(
+ sym::rustc_host,
span,
- id: attr_id,
- style: AttrStyle::Outer,
- },
- ]);
+ )))),
+ span,
+ id: attr_id,
+ style: AttrStyle::Outer,
+ }]);
self.attrs.insert(hir_id.local_id, attrs);
let const_body = self.lower_body(|this| {
@@ -1461,7 +1515,11 @@ impl<'hir> LoweringContext<'_, 'hir> {
}),
)),
)),
- default: Some(hir::AnonConst { def_id: anon_const, hir_id: const_id, body: const_body }),
+ default: Some(hir::AnonConst {
+ def_id: anon_const,
+ hir_id: const_id,
+ body: const_body,
+ }),
},
colon_span: None,
pure_wrt_drop: false,
diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs
index 429e62c4a..4a47de128 100644
--- a/compiler/rustc_ast_lowering/src/lib.rs
+++ b/compiler/rustc_ast_lowering/src/lib.rs
@@ -142,16 +142,14 @@ struct LoweringContext<'a, 'hir> {
/// defined on the TAIT, so we have type Foo<'a1> = ... and we establish a mapping in this
/// field from the original parameter 'a to the new parameter 'a1.
generics_def_id_map: Vec<FxHashMap<LocalDefId, LocalDefId>>,
+
+ host_param_id: Option<LocalDefId>,
}
trait ResolverAstLoweringExt {
fn legacy_const_generic_args(&self, expr: &Expr) -> Option<Vec<usize>>;
fn get_partial_res(&self, id: NodeId) -> Option<PartialRes>;
fn get_import_res(&self, id: NodeId) -> PerNS<Option<Res<NodeId>>>;
- // Clones the resolution (if any) on 'source' and applies it
- // to 'target'. Used when desugaring a `UseTreeKind::Nested` to
- // multiple `UseTreeKind::Simple`s
- fn clone_res(&mut self, source: NodeId, target: NodeId);
fn get_label_res(&self, id: NodeId) -> Option<NodeId>;
fn get_lifetime_res(&self, id: NodeId) -> Option<LifetimeRes>;
fn take_extra_lifetime_params(&mut self, id: NodeId) -> Vec<(Ident, NodeId, LifetimeRes)>;
@@ -184,12 +182,6 @@ impl ResolverAstLoweringExt for ResolverAstLowering {
None
}
- fn clone_res(&mut self, source: NodeId, target: NodeId) {
- if let Some(res) = self.partial_res_map.get(&source) {
- self.partial_res_map.insert(target, *res);
- }
- }
-
/// Obtains resolution for a `NodeId` with a single resolution.
fn get_partial_res(&self, id: NodeId) -> Option<PartialRes> {
self.partial_res_map.get(&id).copied()
@@ -465,7 +457,7 @@ pub fn lower_to_hir(tcx: TyCtxt<'_>, (): ()) -> hir::Crate<'_> {
// Don't hash unless necessary, because it's expensive.
let opt_hir_hash =
- if tcx.sess.needs_crate_hash() { Some(compute_hir_hash(tcx, &owners)) } else { None };
+ if tcx.needs_crate_hash() { Some(compute_hir_hash(tcx, &owners)) } else { None };
hir::Crate { owners, opt_hir_hash }
}
@@ -522,11 +514,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
self.resolver.node_id_to_def_id.get(&node).map(|local_def_id| *local_def_id)
}
- fn orig_local_def_id(&self, node: NodeId) -> LocalDefId {
- self.orig_opt_local_def_id(node)
- .unwrap_or_else(|| panic!("no entry for node id: `{node:?}`"))
- }
-
/// Given the id of some node in the AST, finds the `LocalDefId` associated with it by the name
/// resolver (if any), after applying any remapping from `get_remapped_def_id`.
///
@@ -661,7 +648,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
let bodies = SortedMap::from_presorted_elements(bodies);
// Don't hash unless necessary, because it's expensive.
- let (opt_hash_including_bodies, attrs_hash) = if self.tcx.sess.needs_crate_hash() {
+ let (opt_hash_including_bodies, attrs_hash) = if self.tcx.needs_crate_hash() {
self.tcx.with_stable_hashing_context(|mut hcx| {
let mut stable_hasher = StableHasher::new();
hcx.with_hir_bodies(node.def_id(), &bodies, |hcx| {
@@ -1277,6 +1264,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
span: t.span
},
itctx,
+ ast::Const::No,
);
let bounds = this.arena.alloc_from_iter([bound]);
let lifetime_bound = this.elided_dyn_bound(t.span);
@@ -1287,7 +1275,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
}
let id = self.lower_node_id(t.id);
- let qpath = self.lower_qpath(t.id, qself, path, param_mode, itctx);
+ let qpath = self.lower_qpath(t.id, qself, path, param_mode, itctx, None);
self.ty_path(id, t.span, qpath)
}
@@ -1371,10 +1359,12 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
this.arena.alloc_from_iter(bounds.iter().filter_map(|bound| match bound {
GenericBound::Trait(
ty,
- TraitBoundModifier::None
+ modifier @ (TraitBoundModifier::None
| TraitBoundModifier::MaybeConst
- | TraitBoundModifier::Negative,
- ) => Some(this.lower_poly_trait_ref(ty, itctx)),
+ | TraitBoundModifier::Negative),
+ ) => {
+ Some(this.lower_poly_trait_ref(ty, itctx, modifier.to_constness()))
+ }
// `~const ?Bound` will cause an error during AST validation
// anyways, so treat it like `?Bound` as compilation proceeds.
GenericBound::Trait(
@@ -1531,207 +1521,86 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
// frequently opened issues show.
let opaque_ty_span = self.mark_span_with_reason(DesugaringKind::OpaqueTy, span, None);
- let opaque_ty_def_id = self.create_def(
- self.current_hir_id_owner.def_id,
- opaque_ty_node_id,
- DefPathData::ImplTrait,
- opaque_ty_span,
- );
- debug!(?opaque_ty_def_id);
-
- // If this came from a TAIT (as opposed to a function that returns an RPIT), we only want
- // to capture the lifetimes that appear in the bounds. So visit the bounds to find out
- // exactly which ones those are.
- let lifetimes_to_remap = match origin {
+ let captured_lifetimes_to_duplicate = match origin {
hir::OpaqueTyOrigin::TyAlias { .. } => {
- // in a TAIT like `type Foo<'a> = impl Foo<'a>`, we don't keep all the lifetime parameters
+ // in a TAIT like `type Foo<'a> = impl Foo<'a>`, we don't duplicate any
+ // lifetimes, since we don't have the issue that any are late-bound.
Vec::new()
}
- hir::OpaqueTyOrigin::AsyncFn(..) | hir::OpaqueTyOrigin::FnReturn(..) => {
- // in fn return position, like the `fn test<'a>() -> impl Debug + 'a` example,
- // we only keep the lifetimes that appear in the `impl Debug` itself:
+ hir::OpaqueTyOrigin::FnReturn(..) => {
+ // in fn return position, like the `fn test<'a>() -> impl Debug + 'a`
+ // example, we only need to duplicate lifetimes that appear in the
+ // bounds, since those are the only ones that are captured by the opaque.
lifetime_collector::lifetimes_in_bounds(&self.resolver, bounds)
}
+ hir::OpaqueTyOrigin::AsyncFn(..) => {
+ unreachable!("should be using `lower_async_fn_ret_ty`")
+ }
};
- debug!(?lifetimes_to_remap);
-
- let mut new_remapping = FxHashMap::default();
-
- // Contains the new lifetime definitions created for the TAIT (if any).
- // If this opaque type is only capturing a subset of the lifetimes (those that appear in
- // bounds), then create the new lifetime parameters required and create a mapping from the
- // old `'a` (on the function) to the new `'a` (on the opaque type).
- let collected_lifetimes =
- self.create_lifetime_defs(opaque_ty_def_id, &lifetimes_to_remap, &mut new_remapping);
- debug!(?collected_lifetimes);
- debug!(?new_remapping);
-
- // This creates HIR lifetime arguments as `hir::GenericArg`, in the given example `type
- // TestReturn<'a, T, 'x> = impl Debug + 'x`, it creates a collection containing `&['x]`.
- let collected_lifetime_mapping: Vec<_> = collected_lifetimes
- .iter()
- .map(|(node_id, lifetime)| {
- let id = self.next_node_id();
- let lifetime = self.new_named_lifetime(lifetime.id, id, lifetime.ident);
- let def_id = self.local_def_id(*node_id);
- (lifetime, def_id)
- })
- .collect();
- debug!(?collected_lifetime_mapping);
-
- self.with_hir_id_owner(opaque_ty_node_id, |lctx| {
- // Install the remapping from old to new (if any):
- lctx.with_remapping(new_remapping, |lctx| {
- // This creates HIR lifetime definitions as `hir::GenericParam`, in the given
- // example `type TestReturn<'a, T, 'x> = impl Debug + 'x`, it creates a collection
- // containing `&['x]`.
- let lifetime_defs = lctx.arena.alloc_from_iter(collected_lifetimes.iter().map(
- |&(new_node_id, lifetime)| {
- let hir_id = lctx.lower_node_id(new_node_id);
- debug_assert_ne!(lctx.opt_local_def_id(new_node_id), None);
-
- let (name, kind) = if lifetime.ident.name == kw::UnderscoreLifetime {
- (hir::ParamName::Fresh, hir::LifetimeParamKind::Elided)
- } else {
- (
- hir::ParamName::Plain(lifetime.ident),
- hir::LifetimeParamKind::Explicit,
- )
- };
+ debug!(?captured_lifetimes_to_duplicate);
- hir::GenericParam {
- hir_id,
- def_id: lctx.local_def_id(new_node_id),
- name,
- span: lifetime.ident.span,
- pure_wrt_drop: false,
- kind: hir::GenericParamKind::Lifetime { kind },
- colon_span: None,
- source: hir::GenericParamSource::Generics,
- }
- },
- ));
- debug!(?lifetime_defs);
-
- // Then when we lower the param bounds, references to 'a are remapped to 'a1, so we
- // get back Debug + 'a1, which is suitable for use on the TAIT.
- let hir_bounds = lctx.lower_param_bounds(bounds, itctx);
- debug!(?hir_bounds);
-
- let lifetime_mapping = if in_trait {
- self.arena.alloc_from_iter(
- collected_lifetime_mapping
- .iter()
- .map(|(lifetime, def_id)| (**lifetime, *def_id)),
- )
- } else {
- &mut []
- };
-
- let opaque_ty_item = hir::OpaqueTy {
- generics: self.arena.alloc(hir::Generics {
- params: lifetime_defs,
- predicates: &[],
- has_where_clause_predicates: false,
- where_clause_span: lctx.lower_span(span),
- span: lctx.lower_span(span),
- }),
- bounds: hir_bounds,
- origin,
- lifetime_mapping,
- in_trait,
- };
- debug!(?opaque_ty_item);
-
- lctx.generate_opaque_type(opaque_ty_def_id, opaque_ty_item, span, opaque_ty_span)
- })
- });
-
- // `impl Trait` now just becomes `Foo<'a, 'b, ..>`.
- hir::TyKind::OpaqueDef(
- hir::ItemId { owner_id: hir::OwnerId { def_id: opaque_ty_def_id } },
- self.arena.alloc_from_iter(
- collected_lifetime_mapping
- .iter()
- .map(|(lifetime, _)| hir::GenericArg::Lifetime(*lifetime)),
- ),
+ self.lower_opaque_inner(
+ opaque_ty_node_id,
+ origin,
in_trait,
+ captured_lifetimes_to_duplicate,
+ span,
+ opaque_ty_span,
+ |this| this.lower_param_bounds(bounds, itctx),
)
}
- /// Registers a new opaque type with the proper `NodeId`s and
- /// returns the lowered node-ID for the opaque type.
- fn generate_opaque_type(
+ fn lower_opaque_inner(
&mut self,
- opaque_ty_id: LocalDefId,
- opaque_ty_item: hir::OpaqueTy<'hir>,
+ opaque_ty_node_id: NodeId,
+ origin: hir::OpaqueTyOrigin,
+ in_trait: bool,
+ captured_lifetimes_to_duplicate: Vec<Lifetime>,
span: Span,
opaque_ty_span: Span,
- ) -> hir::OwnerNode<'hir> {
- let opaque_ty_item_kind = hir::ItemKind::OpaqueTy(self.arena.alloc(opaque_ty_item));
- // Generate an `type Foo = impl Trait;` declaration.
- trace!("registering opaque type with id {:#?}", opaque_ty_id);
- let opaque_ty_item = hir::Item {
- owner_id: hir::OwnerId { def_id: opaque_ty_id },
- ident: Ident::empty(),
- kind: opaque_ty_item_kind,
- vis_span: self.lower_span(span.shrink_to_lo()),
- span: self.lower_span(opaque_ty_span),
- };
- hir::OwnerNode::Item(self.arena.alloc(opaque_ty_item))
- }
-
- /// Given a `parent_def_id`, a list of `lifetimes_in_bounds` and a `remapping` hash to be
- /// filled, this function creates new definitions for `Param` and `Fresh` lifetimes, inserts the
- /// new definition, adds it to the remapping with the definition of the given lifetime and
- /// returns a list of lifetimes to be lowered afterwards.
- fn create_lifetime_defs(
- &mut self,
- parent_def_id: LocalDefId,
- lifetimes_in_bounds: &[Lifetime],
- remapping: &mut FxHashMap<LocalDefId, LocalDefId>,
- ) -> Vec<(NodeId, Lifetime)> {
- let mut result = Vec::new();
+ lower_item_bounds: impl FnOnce(&mut Self) -> &'hir [hir::GenericBound<'hir>],
+ ) -> hir::TyKind<'hir> {
+ let opaque_ty_def_id = self.create_def(
+ self.current_hir_id_owner.def_id,
+ opaque_ty_node_id,
+ DefPathData::ImplTrait,
+ opaque_ty_span,
+ );
+ debug!(?opaque_ty_def_id);
- for lifetime in lifetimes_in_bounds {
+ // Map from captured (old) lifetime to synthetic (new) lifetime.
+ // Used to resolve lifetimes in the bounds of the opaque.
+ let mut captured_to_synthesized_mapping = FxHashMap::default();
+ // List of (early-bound) synthetic lifetimes that are owned by the opaque.
+ // This is used to create the `hir::Generics` owned by the opaque.
+ let mut synthesized_lifetime_definitions = vec![];
+ // Pairs of lifetime arg (that resolves to the captured lifetime)
+ // and the def-id of the (early-bound) synthetic lifetime definition.
+ // This is used both to create generics for the `TyKind::OpaqueDef` that
+ // we return, and also as a captured lifetime mapping for RPITITs.
+ let mut synthesized_lifetime_args = vec![];
+
+ for lifetime in captured_lifetimes_to_duplicate {
let res = self.resolver.get_lifetime_res(lifetime.id).unwrap_or(LifetimeRes::Error);
- debug!(?res);
-
- match res {
- LifetimeRes::Param { param: old_def_id, binder: _ } => {
- if remapping.get(&old_def_id).is_none() {
- let node_id = self.next_node_id();
-
- let new_def_id = self.create_def(
- parent_def_id,
- node_id,
- DefPathData::LifetimeNs(lifetime.ident.name),
- lifetime.ident.span,
- );
- remapping.insert(old_def_id, new_def_id);
-
- result.push((node_id, *lifetime));
- }
- }
+ let old_def_id = match res {
+ LifetimeRes::Param { param: old_def_id, binder: _ } => old_def_id,
LifetimeRes::Fresh { param, binder: _ } => {
debug_assert_eq!(lifetime.ident.name, kw::UnderscoreLifetime);
- if let Some(old_def_id) = self.orig_opt_local_def_id(param) && remapping.get(&old_def_id).is_none() {
- let node_id = self.next_node_id();
-
- let new_def_id = self.create_def(
- parent_def_id,
- node_id,
- DefPathData::LifetimeNs(kw::UnderscoreLifetime),
- lifetime.ident.span,
- );
- remapping.insert(old_def_id, new_def_id);
-
- result.push((node_id, *lifetime));
+ if let Some(old_def_id) = self.orig_opt_local_def_id(param) {
+ old_def_id
+ } else {
+ self.tcx
+ .sess
+ .delay_span_bug(lifetime.ident.span, "no def-id for fresh lifetime");
+ continue;
}
}
- LifetimeRes::Static | LifetimeRes::Error => {}
+ // Opaques do not capture `'static`
+ LifetimeRes::Static | LifetimeRes::Error => {
+ continue;
+ }
res => {
let bug_msg = format!(
@@ -1740,10 +1609,109 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
);
span_bug!(lifetime.ident.span, "{}", bug_msg);
}
+ };
+
+ if captured_to_synthesized_mapping.get(&old_def_id).is_none() {
+ // Create a new lifetime parameter local to the opaque.
+ let duplicated_lifetime_node_id = self.next_node_id();
+ let duplicated_lifetime_def_id = self.create_def(
+ opaque_ty_def_id,
+ duplicated_lifetime_node_id,
+ DefPathData::LifetimeNs(lifetime.ident.name),
+ lifetime.ident.span,
+ );
+ captured_to_synthesized_mapping.insert(old_def_id, duplicated_lifetime_def_id);
+ // FIXME: Instead of doing this, we could move this whole loop
+ // into the `with_hir_id_owner`, then just directly construct
+ // the `hir::GenericParam` here.
+ synthesized_lifetime_definitions.push((
+ duplicated_lifetime_node_id,
+ duplicated_lifetime_def_id,
+ lifetime.ident,
+ ));
+
+ // Now make an arg that we can use for the substs of the opaque tykind.
+ let id = self.next_node_id();
+ let lifetime_arg = self.new_named_lifetime_with_res(id, lifetime.ident, res);
+ let duplicated_lifetime_def_id = self.local_def_id(duplicated_lifetime_node_id);
+ synthesized_lifetime_args.push((lifetime_arg, duplicated_lifetime_def_id))
}
}
- result
+ self.with_hir_id_owner(opaque_ty_node_id, |this| {
+ // Install the remapping from old to new (if any). This makes sure that
+ // any lifetimes that would have resolved to the def-id of captured
+ // lifetimes are remapped to the new *synthetic* lifetimes of the opaque.
+ let bounds = this
+ .with_remapping(captured_to_synthesized_mapping, |this| lower_item_bounds(this));
+
+ let generic_params = this.arena.alloc_from_iter(
+ synthesized_lifetime_definitions.iter().map(|&(new_node_id, new_def_id, ident)| {
+ let hir_id = this.lower_node_id(new_node_id);
+ let (name, kind) = if ident.name == kw::UnderscoreLifetime {
+ (hir::ParamName::Fresh, hir::LifetimeParamKind::Elided)
+ } else {
+ (hir::ParamName::Plain(ident), hir::LifetimeParamKind::Explicit)
+ };
+
+ hir::GenericParam {
+ hir_id,
+ def_id: new_def_id,
+ name,
+ span: ident.span,
+ pure_wrt_drop: false,
+ kind: hir::GenericParamKind::Lifetime { kind },
+ colon_span: None,
+ source: hir::GenericParamSource::Generics,
+ }
+ }),
+ );
+ debug!("lower_async_fn_ret_ty: generic_params={:#?}", generic_params);
+
+ let lifetime_mapping = self.arena.alloc_slice(&synthesized_lifetime_args);
+
+ let opaque_ty_item = hir::OpaqueTy {
+ generics: this.arena.alloc(hir::Generics {
+ params: generic_params,
+ predicates: &[],
+ has_where_clause_predicates: false,
+ where_clause_span: this.lower_span(span),
+ span: this.lower_span(span),
+ }),
+ bounds,
+ origin,
+ lifetime_mapping,
+ in_trait,
+ };
+
+ // Generate an `type Foo = impl Trait;` declaration.
+ trace!("registering opaque type with id {:#?}", opaque_ty_def_id);
+ let opaque_ty_item = hir::Item {
+ owner_id: hir::OwnerId { def_id: opaque_ty_def_id },
+ ident: Ident::empty(),
+ kind: hir::ItemKind::OpaqueTy(this.arena.alloc(opaque_ty_item)),
+ vis_span: this.lower_span(span.shrink_to_lo()),
+ span: this.lower_span(opaque_ty_span),
+ };
+
+ hir::OwnerNode::Item(this.arena.alloc(opaque_ty_item))
+ });
+
+ let generic_args = self.arena.alloc_from_iter(
+ synthesized_lifetime_args
+ .iter()
+ .map(|(lifetime, _)| hir::GenericArg::Lifetime(*lifetime)),
+ );
+
+ // Create the `Foo<...>` reference itself. Note that the `type
+ // Foo = impl Trait` is, internally, created as a child of the
+ // async fn, so the *type parameters* are inherited. It's
+ // only the lifetime parameters that we must supply.
+ hir::TyKind::OpaqueDef(
+ hir::ItemId { owner_id: hir::OwnerId { def_id: opaque_ty_def_id } },
+ generic_args,
+ in_trait,
+ )
}
fn lower_fn_params_to_names(&mut self, decl: &FnDecl) -> &'hir [Ident] {
@@ -1821,9 +1789,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
}
}
+ let fn_def_id = self.local_def_id(fn_node_id);
self.lower_async_fn_ret_ty(
&decl.output,
- fn_node_id,
+ fn_def_id,
ret_id,
matches!(kind, FnDeclKind::Trait),
)
@@ -1900,151 +1869,28 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
fn lower_async_fn_ret_ty(
&mut self,
output: &FnRetTy,
- fn_node_id: NodeId,
+ fn_def_id: LocalDefId,
opaque_ty_node_id: NodeId,
in_trait: bool,
) -> hir::FnRetTy<'hir> {
- let span = output.span();
-
+ let span = self.lower_span(output.span());
let opaque_ty_span = self.mark_span_with_reason(DesugaringKind::Async, span, None);
- let fn_def_id = self.local_def_id(fn_node_id);
-
- let opaque_ty_def_id =
- self.create_def(fn_def_id, opaque_ty_node_id, DefPathData::ImplTrait, opaque_ty_span);
-
- // When we create the opaque type for this async fn, it is going to have
- // to capture all the lifetimes involved in the signature (including in the
- // return type). This is done by introducing lifetime parameters for:
- //
- // - all the explicitly declared lifetimes from the impl and function itself;
- // - all the elided lifetimes in the fn arguments;
- // - all the elided lifetimes in the return type.
- //
- // So for example in this snippet:
- //
- // ```rust
- // impl<'a> Foo<'a> {
- // async fn bar<'b>(&self, x: &'b Vec<f64>, y: &str) -> &u32 {
- // // ^ '0 ^ '1 ^ '2
- // // elided lifetimes used below
- // }
- // }
- // ```
- //
- // we would create an opaque type like:
- //
- // ```
- // type Bar<'a, 'b, '0, '1, '2> = impl Future<Output = &'2 u32>;
- // ```
- //
- // and we would then desugar `bar` to the equivalent of:
- //
- // ```rust
- // impl<'a> Foo<'a> {
- // fn bar<'b, '0, '1>(&'0 self, x: &'b Vec<f64>, y: &'1 str) -> Bar<'a, 'b, '0, '1, '_>
- // }
- // ```
- //
- // Note that the final parameter to `Bar` is `'_`, not `'2` --
- // this is because the elided lifetimes from the return type
- // should be figured out using the ordinary elision rules, and
- // this desugaring achieves that.
-
- // Calculate all the lifetimes that should be captured
- // by the opaque type. This should include all in-scope
- // lifetime parameters, including those defined in-band.
-
- // Contains the new lifetime definitions created for the TAIT (if any) generated for the
- // return type.
- let mut collected_lifetimes = Vec::new();
- let mut new_remapping = FxHashMap::default();
-
- let extra_lifetime_params = self.resolver.take_extra_lifetime_params(opaque_ty_node_id);
- debug!(?extra_lifetime_params);
- for (ident, outer_node_id, outer_res) in extra_lifetime_params {
- let outer_def_id = self.orig_local_def_id(outer_node_id);
- let inner_node_id = self.next_node_id();
-
- // Add a definition for the in scope lifetime def.
- let inner_def_id = self.create_def(
- opaque_ty_def_id,
- inner_node_id,
- DefPathData::LifetimeNs(ident.name),
- ident.span,
- );
- new_remapping.insert(outer_def_id, inner_def_id);
-
- let inner_res = match outer_res {
- // Input lifetime like `'a`:
- LifetimeRes::Param { param, .. } => {
- LifetimeRes::Param { param, binder: fn_node_id }
- }
- // Input lifetime like `'1`:
- LifetimeRes::Fresh { param, .. } => {
- LifetimeRes::Fresh { param, binder: fn_node_id }
- }
- LifetimeRes::Static | LifetimeRes::Error => continue,
- res => {
- panic!(
- "Unexpected lifetime resolution {:?} for {:?} at {:?}",
- res, ident, ident.span
- )
- }
- };
-
- let lifetime = Lifetime { id: outer_node_id, ident };
- collected_lifetimes.push((inner_node_id, lifetime, Some(inner_res)));
- }
- debug!(?collected_lifetimes);
-
- // We only want to capture the lifetimes that appear in the bounds. So visit the bounds to
- // find out exactly which ones those are.
- // in fn return position, like the `fn test<'a>() -> impl Debug + 'a` example,
- // we only keep the lifetimes that appear in the `impl Debug` itself:
- let lifetimes_to_remap = lifetime_collector::lifetimes_in_ret_ty(&self.resolver, output);
- debug!(?lifetimes_to_remap);
-
- // If this opaque type is only capturing a subset of the lifetimes (those that appear in
- // bounds), then create the new lifetime parameters required and create a mapping from the
- // old `'a` (on the function) to the new `'a` (on the opaque type).
- collected_lifetimes.extend(
- self.create_lifetime_defs(opaque_ty_def_id, &lifetimes_to_remap, &mut new_remapping)
- .into_iter()
- .map(|(new_node_id, lifetime)| (new_node_id, lifetime, None)),
- );
- debug!(?collected_lifetimes);
- debug!(?new_remapping);
-
- // This creates pairs of HIR lifetimes and def_ids. In the given example `type
- // TestReturn<'a, T, 'x> = impl Debug + 'x`, it creates a collection containing the
- // new lifetime of the RPIT 'x and the def_id of the lifetime 'x corresponding to
- // `TestReturn`.
- let collected_lifetime_mapping: Vec<_> = collected_lifetimes
- .iter()
- .map(|(node_id, lifetime, res)| {
- let id = self.next_node_id();
- let res = res.unwrap_or(
- self.resolver.get_lifetime_res(lifetime.id).unwrap_or(LifetimeRes::Error),
- );
- let lifetime = self.new_named_lifetime_with_res(id, lifetime.ident, res);
- let def_id = self.local_def_id(*node_id);
- (lifetime, def_id)
- })
+ let captured_lifetimes: Vec<_> = self
+ .resolver
+ .take_extra_lifetime_params(opaque_ty_node_id)
+ .into_iter()
+ .map(|(ident, id, _)| Lifetime { id, ident })
.collect();
- debug!(?collected_lifetime_mapping);
- self.with_hir_id_owner(opaque_ty_node_id, |this| {
- // Install the remapping from old to new (if any):
- this.with_remapping(new_remapping, |this| {
- // We have to be careful to get elision right here. The
- // idea is that we create a lifetime parameter for each
- // lifetime in the return type. So, given a return type
- // like `async fn foo(..) -> &[&u32]`, we lower to `impl
- // Future<Output = &'1 [ &'2 u32 ]>`.
- //
- // Then, we will create `fn foo(..) -> Foo<'_, '_>`, and
- // hence the elision takes place at the fn site.
+ let opaque_ty_ref = self.lower_opaque_inner(
+ opaque_ty_node_id,
+ hir::OpaqueTyOrigin::AsyncFn(fn_def_id),
+ in_trait,
+ captured_lifetimes,
+ span,
+ opaque_ty_span,
+ |this| {
let future_bound = this.lower_async_fn_output_type_to_future_bound(
output,
span,
@@ -2060,94 +1906,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
}
},
);
-
- let generic_params = this.arena.alloc_from_iter(collected_lifetimes.iter().map(
- |&(new_node_id, lifetime, _)| {
- let hir_id = this.lower_node_id(new_node_id);
- debug_assert_ne!(this.opt_local_def_id(new_node_id), None);
-
- let (name, kind) = if lifetime.ident.name == kw::UnderscoreLifetime {
- (hir::ParamName::Fresh, hir::LifetimeParamKind::Elided)
- } else {
- (
- hir::ParamName::Plain(lifetime.ident),
- hir::LifetimeParamKind::Explicit,
- )
- };
-
- hir::GenericParam {
- hir_id,
- def_id: this.local_def_id(new_node_id),
- name,
- span: lifetime.ident.span,
- pure_wrt_drop: false,
- kind: hir::GenericParamKind::Lifetime { kind },
- colon_span: None,
- source: hir::GenericParamSource::Generics,
- }
- },
- ));
- debug!("lower_async_fn_ret_ty: generic_params={:#?}", generic_params);
-
- let lifetime_mapping = if in_trait {
- self.arena.alloc_from_iter(
- collected_lifetime_mapping
- .iter()
- .map(|(lifetime, def_id)| (**lifetime, *def_id)),
- )
- } else {
- &mut []
- };
-
- let opaque_ty_item = hir::OpaqueTy {
- generics: this.arena.alloc(hir::Generics {
- params: generic_params,
- predicates: &[],
- has_where_clause_predicates: false,
- where_clause_span: this.lower_span(span),
- span: this.lower_span(span),
- }),
- bounds: arena_vec![this; future_bound],
- origin: hir::OpaqueTyOrigin::AsyncFn(fn_def_id),
- lifetime_mapping,
- in_trait,
- };
-
- trace!("exist ty from async fn def id: {:#?}", opaque_ty_def_id);
- this.generate_opaque_type(opaque_ty_def_id, opaque_ty_item, span, opaque_ty_span)
- })
- });
-
- // As documented above, we need to create the lifetime
- // arguments to our opaque type. Continuing with our example,
- // we're creating the type arguments for the return type:
- //
- // ```
- // Bar<'a, 'b, '0, '1, '_>
- // ```
- //
- // For the "input" lifetime parameters, we wish to create
- // references to the parameters themselves, including the
- // "implicit" ones created from parameter types (`'a`, `'b`,
- // '`0`, `'1`).
- //
- // For the "output" lifetime parameters, we just want to
- // generate `'_`.
- let generic_args = self.arena.alloc_from_iter(
- collected_lifetime_mapping
- .iter()
- .map(|(lifetime, _)| hir::GenericArg::Lifetime(*lifetime)),
+ arena_vec![this; future_bound]
+ },
);
- // Create the `Foo<...>` reference itself. Note that the `type
- // Foo = impl Trait` is, internally, created as a child of the
- // async fn, so the *type parameters* are inherited. It's
- // only the lifetime parameters that we must supply.
- let opaque_ty_ref = hir::TyKind::OpaqueDef(
- hir::ItemId { owner_id: hir::OwnerId { def_id: opaque_ty_def_id } },
- generic_args,
- in_trait,
- );
let opaque_ty = self.ty(opaque_ty_span, opaque_ty_ref);
hir::FnRetTy::Return(self.arena.alloc(opaque_ty))
}
@@ -2195,7 +1957,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
) -> hir::GenericBound<'hir> {
match tpb {
GenericBound::Trait(p, modifier) => hir::GenericBound::Trait(
- self.lower_poly_trait_ref(p, itctx),
+ self.lower_poly_trait_ref(p, itctx, modifier.to_constness()),
self.lower_trait_bound_modifier(*modifier),
),
GenericBound::Outlives(lifetime) => {
@@ -2338,8 +2100,20 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
}
}
- fn lower_trait_ref(&mut self, p: &TraitRef, itctx: &ImplTraitContext) -> hir::TraitRef<'hir> {
- let path = match self.lower_qpath(p.ref_id, &None, &p.path, ParamMode::Explicit, itctx) {
+ fn lower_trait_ref(
+ &mut self,
+ constness: ast::Const,
+ p: &TraitRef,
+ itctx: &ImplTraitContext,
+ ) -> hir::TraitRef<'hir> {
+ let path = match self.lower_qpath(
+ p.ref_id,
+ &None,
+ &p.path,
+ ParamMode::Explicit,
+ itctx,
+ Some(constness),
+ ) {
hir::QPath::Resolved(None, path) => path,
qpath => panic!("lower_trait_ref: unexpected QPath `{qpath:?}`"),
};
@@ -2351,10 +2125,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
&mut self,
p: &PolyTraitRef,
itctx: &ImplTraitContext,
+ constness: ast::Const,
) -> hir::PolyTraitRef<'hir> {
let bound_generic_params =
self.lower_lifetime_binder(p.trait_ref.ref_id, &p.bound_generic_params);
- let trait_ref = self.lower_trait_ref(&p.trait_ref, itctx);
+ let trait_ref = self.lower_trait_ref(constness, &p.trait_ref, itctx);
hir::PolyTraitRef { bound_generic_params, trait_ref, span: self.lower_span(p.span) }
}
@@ -2708,6 +2483,63 @@ struct GenericArgsCtor<'hir> {
}
impl<'hir> GenericArgsCtor<'hir> {
+ fn push_constness(&mut self, lcx: &mut LoweringContext<'_, 'hir>, constness: ast::Const) {
+ if !lcx.tcx.features().effects {
+ return;
+ }
+
+ // if bound is non-const, don't add host effect param
+ let ast::Const::Yes(span) = constness else { return };
+
+ let span = lcx.lower_span(span);
+
+ let id = lcx.next_node_id();
+ let hir_id = lcx.next_id();
+
+ let Some(host_param_id) = lcx.host_param_id else {
+ lcx.tcx
+ .sess
+ .delay_span_bug(span, "no host param id for call in const yet no errors reported");
+ return;
+ };
+
+ let body = lcx.lower_body(|lcx| {
+ (&[], {
+ let hir_id = lcx.next_id();
+ let res = Res::Def(DefKind::ConstParam, host_param_id.to_def_id());
+ let expr_kind = hir::ExprKind::Path(hir::QPath::Resolved(
+ None,
+ lcx.arena.alloc(hir::Path {
+ span,
+ res,
+ segments: arena_vec![lcx; hir::PathSegment::new(Ident {
+ name: sym::host,
+ span,
+ }, hir_id, res)],
+ }),
+ ));
+ lcx.expr(span, expr_kind)
+ })
+ });
+
+ let attr_id = lcx.tcx.sess.parse_sess.attr_id_generator.mk_attr_id();
+ let attr = lcx.arena.alloc(Attribute {
+ kind: AttrKind::Normal(P(NormalAttr::from_ident(Ident::new(sym::rustc_host, span)))),
+ span,
+ id: attr_id,
+ style: AttrStyle::Outer,
+ });
+ lcx.attrs.insert(hir_id.local_id, std::slice::from_ref(attr));
+
+ let def_id =
+ lcx.create_def(lcx.current_hir_id_owner.def_id, id, DefPathData::AnonConst, span);
+ lcx.children.push((def_id, hir::MaybeOwner::NonOwner(hir_id)));
+ self.args.push(hir::GenericArg::Const(hir::ConstArg {
+ value: hir::AnonConst { def_id, hir_id, body },
+ span,
+ }))
+ }
+
fn is_empty(&self) -> bool {
self.args.is_empty()
&& self.bindings.is_empty()
diff --git a/compiler/rustc_ast_lowering/src/lifetime_collector.rs b/compiler/rustc_ast_lowering/src/lifetime_collector.rs
index 3989fc486..6f75419c3 100644
--- a/compiler/rustc_ast_lowering/src/lifetime_collector.rs
+++ b/compiler/rustc_ast_lowering/src/lifetime_collector.rs
@@ -1,7 +1,7 @@
use super::ResolverAstLoweringExt;
use rustc_ast::visit::{self, BoundKind, LifetimeCtxt, Visitor};
-use rustc_ast::{FnRetTy, GenericBounds, Lifetime, NodeId, PathSegment, PolyTraitRef, Ty, TyKind};
-use rustc_hir::def::LifetimeRes;
+use rustc_ast::{GenericBounds, Lifetime, NodeId, PathSegment, PolyTraitRef, Ty, TyKind};
+use rustc_hir::def::{DefKind, LifetimeRes, Res};
use rustc_middle::span_bug;
use rustc_middle::ty::ResolverAstLowering;
use rustc_span::symbol::{kw, Ident};
@@ -77,7 +77,20 @@ impl<'ast> Visitor<'ast> for LifetimeCollectVisitor<'ast> {
}
fn visit_ty(&mut self, t: &'ast Ty) {
- match t.kind {
+ match &t.kind {
+ TyKind::Path(None, _) => {
+ // We can sometimes encounter bare trait objects
+ // which are represented in AST as paths.
+ if let Some(partial_res) = self.resolver.get_partial_res(t.id)
+ && let Some(Res::Def(DefKind::Trait | DefKind::TraitAlias, _)) = partial_res.full_res()
+ {
+ self.current_binders.push(t.id);
+ visit::walk_ty(self, t);
+ self.current_binders.pop();
+ } else {
+ visit::walk_ty(self, t);
+ }
+ }
TyKind::BareFn(_) => {
self.current_binders.push(t.id);
visit::walk_ty(self, t);
@@ -94,12 +107,6 @@ impl<'ast> Visitor<'ast> for LifetimeCollectVisitor<'ast> {
}
}
-pub fn lifetimes_in_ret_ty(resolver: &ResolverAstLowering, ret_ty: &FnRetTy) -> Vec<Lifetime> {
- let mut visitor = LifetimeCollectVisitor::new(resolver);
- visitor.visit_fn_ret_ty(ret_ty);
- visitor.collected_lifetimes
-}
-
pub fn lifetimes_in_bounds(
resolver: &ResolverAstLowering,
bounds: &GenericBounds,
diff --git a/compiler/rustc_ast_lowering/src/pat.rs b/compiler/rustc_ast_lowering/src/pat.rs
index 2509b7056..a30f264bc 100644
--- a/compiler/rustc_ast_lowering/src/pat.rs
+++ b/compiler/rustc_ast_lowering/src/pat.rs
@@ -38,6 +38,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
path,
ParamMode::Optional,
&ImplTraitContext::Disallowed(ImplTraitPosition::Path),
+ None,
);
let (pats, ddpos) = self.lower_pat_tuple(pats, "tuple struct");
break hir::PatKind::TupleStruct(qpath, pats, ddpos);
@@ -54,6 +55,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
path,
ParamMode::Optional,
&ImplTraitContext::Disallowed(ImplTraitPosition::Path),
+ None,
);
break hir::PatKind::Path(qpath);
}
@@ -64,6 +66,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
path,
ParamMode::Optional,
&ImplTraitContext::Disallowed(ImplTraitPosition::Path),
+ None,
);
let fs = self.arena.alloc_from_iter(fields.iter().map(|f| {
diff --git a/compiler/rustc_ast_lowering/src/path.rs b/compiler/rustc_ast_lowering/src/path.rs
index 441282c05..899f92a99 100644
--- a/compiler/rustc_ast_lowering/src/path.rs
+++ b/compiler/rustc_ast_lowering/src/path.rs
@@ -23,6 +23,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
p: &Path,
param_mode: ParamMode,
itctx: &ImplTraitContext,
+ // constness of the impl/bound if this is a trait path
+ constness: Option<ast::Const>,
) -> hir::QPath<'hir> {
let qself_position = qself.as_ref().map(|q| q.position);
let qself = qself.as_ref().map(|q| self.lower_ty(&q.ty, itctx));
@@ -73,6 +75,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
param_mode,
parenthesized_generic_args,
itctx,
+ // if this is the last segment, add constness to the trait path
+ if i == proj_start - 1 { constness } else { None },
)
},
)),
@@ -119,6 +123,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
param_mode,
ParenthesizedGenericArgs::Err,
itctx,
+ None,
));
let qpath = hir::QPath::TypeRelative(ty, hir_segment);
@@ -159,6 +164,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
param_mode,
ParenthesizedGenericArgs::Err,
&ImplTraitContext::Disallowed(ImplTraitPosition::Path),
+ None,
)
})),
span: self.lower_span(p.span),
@@ -172,8 +178,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
param_mode: ParamMode,
parenthesized_generic_args: ParenthesizedGenericArgs,
itctx: &ImplTraitContext,
+ constness: Option<ast::Const>,
) -> hir::PathSegment<'hir> {
- debug!("path_span: {:?}, lower_path_segment(segment: {:?})", path_span, segment,);
+ debug!("path_span: {:?}, lower_path_segment(segment: {:?})", path_span, segment);
let (mut generic_args, infer_args) = if let Some(generic_args) = segment.args.as_deref() {
match generic_args {
GenericArgs::AngleBracketed(data) => {
@@ -231,6 +238,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
)
};
+ if let Some(constness) = constness {
+ generic_args.push_constness(self, constness);
+ }
+
let has_lifetimes =
generic_args.args.iter().any(|arg| matches!(arg, GenericArg::Lifetime(_)));