Rollup merge of #129493 - cjgillot:early-opaque-def, r=petrochenkov

Create opaque definitions in resolver.

Implementing https://github.com/rust-lang/rust/issues/129023#issuecomment-2306079532

That was easier than I expected.

r? `@petrochenkov`
This commit is contained in:
Matthias Krüger 2024-09-01 03:58:04 +02:00 committed by GitHub
commit 07d5c250be
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 91 additions and 97 deletions

View File

@ -69,14 +69,14 @@ pub enum FnKind<'a> {
Fn(FnCtxt, Ident, &'a FnSig, &'a Visibility, &'a Generics, Option<&'a Block>), Fn(FnCtxt, Ident, &'a FnSig, &'a Visibility, &'a Generics, Option<&'a Block>),
/// E.g., `|x, y| body`. /// E.g., `|x, y| body`.
Closure(&'a ClosureBinder, &'a FnDecl, &'a Expr), Closure(&'a ClosureBinder, &'a Option<CoroutineKind>, &'a FnDecl, &'a Expr),
} }
impl<'a> FnKind<'a> { impl<'a> FnKind<'a> {
pub fn header(&self) -> Option<&'a FnHeader> { pub fn header(&self) -> Option<&'a FnHeader> {
match *self { match *self {
FnKind::Fn(_, _, sig, _, _, _) => Some(&sig.header), FnKind::Fn(_, _, sig, _, _, _) => Some(&sig.header),
FnKind::Closure(_, _, _) => None, FnKind::Closure(..) => None,
} }
} }
@ -90,7 +90,7 @@ pub fn ident(&self) -> Option<&Ident> {
pub fn decl(&self) -> &'a FnDecl { pub fn decl(&self) -> &'a FnDecl {
match self { match self {
FnKind::Fn(_, _, sig, _, _, _) => &sig.decl, FnKind::Fn(_, _, sig, _, _, _) => &sig.decl,
FnKind::Closure(_, decl, _) => decl, FnKind::Closure(_, _, decl, _) => decl,
} }
} }
@ -839,7 +839,7 @@ pub fn walk_fn<'a, V: Visitor<'a>>(visitor: &mut V, kind: FnKind<'a>) -> V::Resu
try_visit!(walk_fn_decl(visitor, decl)); try_visit!(walk_fn_decl(visitor, decl));
visit_opt!(visitor, visit_block, body); visit_opt!(visitor, visit_block, body);
} }
FnKind::Closure(binder, decl, body) => { FnKind::Closure(binder, _coroutine_kind, decl, body) => {
try_visit!(visitor.visit_closure_binder(binder)); try_visit!(visitor.visit_closure_binder(binder));
try_visit!(walk_fn_decl(visitor, decl)); try_visit!(walk_fn_decl(visitor, decl));
try_visit!(visitor.visit_expr(body)); try_visit!(visitor.visit_expr(body));
@ -1107,7 +1107,7 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) -> V
ExprKind::Closure(box Closure { ExprKind::Closure(box Closure {
binder, binder,
capture_clause, capture_clause,
coroutine_kind: _, coroutine_kind,
constness: _, constness: _,
movability: _, movability: _,
fn_decl, fn_decl,
@ -1116,7 +1116,11 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) -> V
fn_arg_span: _, fn_arg_span: _,
}) => { }) => {
try_visit!(visitor.visit_capture_by(capture_clause)); try_visit!(visitor.visit_capture_by(capture_clause));
try_visit!(visitor.visit_fn(FnKind::Closure(binder, fn_decl, body), *span, *id)) try_visit!(visitor.visit_fn(
FnKind::Closure(binder, coroutine_kind, fn_decl, body),
*span,
*id
))
} }
ExprKind::Block(block, opt_label) => { ExprKind::Block(block, opt_label) => {
visit_opt!(visitor, visit_label, opt_label); visit_opt!(visitor, visit_label, opt_label);

View File

@ -45,7 +45,6 @@
use rustc_ast::node_id::NodeMap; use rustc_ast::node_id::NodeMap;
use rustc_ast::ptr::P; use rustc_ast::ptr::P;
use rustc_ast::{self as ast, *}; use rustc_ast::{self as ast, *};
use rustc_ast_pretty::pprust;
use rustc_data_structures::captures::Captures; use rustc_data_structures::captures::Captures;
use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::fingerprint::Fingerprint;
use rustc_data_structures::fx::FxIndexSet; use rustc_data_structures::fx::FxIndexSet;
@ -1399,24 +1398,9 @@ fn lower_ty_direct(&mut self, t: &Ty, itctx: ImplTraitContext) -> hir::Ty<'hir>
self.tcx.dcx().emit_err(errors::NoPreciseCapturesOnApit { span }); self.tcx.dcx().emit_err(errors::NoPreciseCapturesOnApit { span });
} }
let span = t.span; let def_id = self.local_def_id(*def_node_id);
let name = self.tcx.item_name(def_id.to_def_id());
// HACK: pprust breaks strings with newlines when the type let ident = Ident::new(name, span);
// gets too long. We don't want these to show up in compiler
// output or built artifacts, so replace them here...
// Perhaps we should instead format APITs more robustly.
let ident = Ident::from_str_and_span(
&pprust::ty_to_string(t).replace('\n', " "),
span,
);
self.create_def(
self.current_hir_id_owner.def_id, // FIXME: should this use self.current_def_id_parent?
*def_node_id,
ident.name,
DefKind::TyParam,
span,
);
let (param, bounds, path) = self.lower_universal_param_and_bounds( let (param, bounds, path) = self.lower_universal_param_and_bounds(
*def_node_id, *def_node_id,
span, span,
@ -1618,13 +1602,7 @@ fn lower_opaque_inner(
opaque_ty_span: Span, opaque_ty_span: Span,
lower_item_bounds: impl FnOnce(&mut Self) -> &'hir [hir::GenericBound<'hir>], lower_item_bounds: impl FnOnce(&mut Self) -> &'hir [hir::GenericBound<'hir>],
) -> hir::TyKind<'hir> { ) -> hir::TyKind<'hir> {
let opaque_ty_def_id = self.create_def( let opaque_ty_def_id = self.local_def_id(opaque_ty_node_id);
self.current_hir_id_owner.def_id, // FIXME: should this use self.current_def_id_parent?
opaque_ty_node_id,
kw::Empty,
DefKind::OpaqueTy,
opaque_ty_span,
);
debug!(?opaque_ty_def_id); debug!(?opaque_ty_def_id);
// Map from captured (old) lifetime to synthetic (new) lifetime. // Map from captured (old) lifetime to synthetic (new) lifetime.

View File

@ -1485,7 +1485,7 @@ fn visit_fn(&mut self, fk: FnKind<'a>, span: Span, id: NodeId) {
let disallowed = (!tilde_const_allowed).then(|| match fk { let disallowed = (!tilde_const_allowed).then(|| match fk {
FnKind::Fn(_, ident, _, _, _, _) => TildeConstReason::Function { ident: ident.span }, FnKind::Fn(_, ident, _, _, _, _) => TildeConstReason::Function { ident: ident.span },
FnKind::Closure(_, _, _) => TildeConstReason::Closure, FnKind::Closure(..) => TildeConstReason::Closure,
}); });
self.with_tilde_const(disallowed, |this| visit::walk_fn(this, fk)); self.with_tilde_const(disallowed, |this| visit::walk_fn(this, fk));
} }

View File

@ -2,6 +2,7 @@
use rustc_ast::visit::FnKind; use rustc_ast::visit::FnKind;
use rustc_ast::*; use rustc_ast::*;
use rustc_ast_pretty::pprust;
use rustc_expand::expand::AstFragment; use rustc_expand::expand::AstFragment;
use rustc_hir as hir; use rustc_hir as hir;
use rustc_hir::def::{CtorKind, CtorOf, DefKind}; use rustc_hir::def::{CtorKind, CtorOf, DefKind};
@ -120,8 +121,6 @@ fn visit_macro_invoc(&mut self, id: NodeId) {
impl<'a, 'b, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'b, 'tcx> { impl<'a, 'b, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'b, 'tcx> {
fn visit_item(&mut self, i: &'a Item) { fn visit_item(&mut self, i: &'a Item) {
debug!("visit_item: {:?}", i);
// Pick the def data. This need not be unique, but the more // Pick the def data. This need not be unique, but the more
// information we encapsulate into, the better // information we encapsulate into, the better
let mut opt_macro_data = None; let mut opt_macro_data = None;
@ -183,38 +182,51 @@ fn visit_item(&mut self, i: &'a Item) {
} }
fn visit_fn(&mut self, fn_kind: FnKind<'a>, span: Span, _: NodeId) { fn visit_fn(&mut self, fn_kind: FnKind<'a>, span: Span, _: NodeId) {
if let FnKind::Fn(_, _, sig, _, generics, body) = fn_kind { match fn_kind {
match sig.header.coroutine_kind { FnKind::Fn(_ctxt, _ident, FnSig { header, decl, span: _ }, _vis, generics, body)
Some(coroutine_kind) => { if let Some(coroutine_kind) = header.coroutine_kind =>
self.visit_generics(generics); {
self.visit_fn_header(header);
self.visit_generics(generics);
// For async functions, we need to create their inner defs inside of a // For async functions, we need to create their inner defs inside of a
// closure to match their desugared representation. Besides that, // closure to match their desugared representation. Besides that,
// we must mirror everything that `visit::walk_fn` below does. // we must mirror everything that `visit::walk_fn` below does.
self.visit_fn_header(&sig.header); let FnDecl { inputs, output } = &**decl;
for param in &sig.decl.inputs { for param in inputs {
self.visit_param(param); self.visit_param(param);
}
self.visit_fn_ret_ty(&sig.decl.output);
// If this async fn has no body (i.e. it's an async fn signature in a trait)
// then the closure_def will never be used, and we should avoid generating a
// def-id for it.
if let Some(body) = body {
let closure_def = self.create_def(
coroutine_kind.closure_id(),
kw::Empty,
DefKind::Closure,
span,
);
self.with_parent(closure_def, |this| this.visit_block(body));
}
return;
} }
None => {}
}
}
visit::walk_fn(self, fn_kind); let (return_id, return_span) = coroutine_kind.return_id();
let return_def =
self.create_def(return_id, kw::Empty, DefKind::OpaqueTy, return_span);
self.with_parent(return_def, |this| this.visit_fn_ret_ty(output));
// If this async fn has no body (i.e. it's an async fn signature in a trait)
// then the closure_def will never be used, and we should avoid generating a
// def-id for it.
if let Some(body) = body {
let closure_def = self.create_def(
coroutine_kind.closure_id(),
kw::Empty,
DefKind::Closure,
span,
);
self.with_parent(closure_def, |this| this.visit_block(body));
}
}
FnKind::Closure(binder, Some(coroutine_kind), decl, body) => {
self.visit_closure_binder(binder);
visit::walk_fn_decl(self, decl);
// Async closures desugar to closures inside of closures, so
// we must create two defs.
let coroutine_def =
self.create_def(coroutine_kind.closure_id(), kw::Empty, DefKind::Closure, span);
self.with_parent(coroutine_def, |this| visit::walk_expr(this, body));
}
_ => visit::walk_fn(self, fn_kind),
}
} }
fn visit_use_tree(&mut self, use_tree: &'a UseTree, id: NodeId, _nested: bool) { fn visit_use_tree(&mut self, use_tree: &'a UseTree, id: NodeId, _nested: bool) {
@ -334,27 +346,7 @@ fn visit_anon_const(&mut self, constant: &'a AnonConst) {
fn visit_expr(&mut self, expr: &'a Expr) { fn visit_expr(&mut self, expr: &'a Expr) {
let parent_def = match expr.kind { let parent_def = match expr.kind {
ExprKind::MacCall(..) => return self.visit_macro_invoc(expr.id), ExprKind::MacCall(..) => return self.visit_macro_invoc(expr.id),
ExprKind::Closure(ref closure) => { ExprKind::Closure(..) | ExprKind::Gen(..) => {
// Async closures desugar to closures inside of closures, so
// we must create two defs.
let closure_def = self.create_def(expr.id, kw::Empty, DefKind::Closure, expr.span);
match closure.coroutine_kind {
Some(coroutine_kind) => {
self.with_parent(closure_def, |this| {
let coroutine_def = this.create_def(
coroutine_kind.closure_id(),
kw::Empty,
DefKind::Closure,
expr.span,
);
this.with_parent(coroutine_def, |this| visit::walk_expr(this, expr));
});
return;
}
None => closure_def,
}
}
ExprKind::Gen(_, _, _, _) => {
self.create_def(expr.id, kw::Empty, DefKind::Closure, expr.span) self.create_def(expr.id, kw::Empty, DefKind::Closure, expr.span)
} }
ExprKind::ConstBlock(ref constant) => { ExprKind::ConstBlock(ref constant) => {
@ -381,6 +373,26 @@ fn visit_ty(&mut self, ty: &'a Ty) {
TyKind::MacCall(..) => self.visit_macro_invoc(ty.id), TyKind::MacCall(..) => self.visit_macro_invoc(ty.id),
// Anonymous structs or unions are visited later after defined. // Anonymous structs or unions are visited later after defined.
TyKind::AnonStruct(..) | TyKind::AnonUnion(..) => {} TyKind::AnonStruct(..) | TyKind::AnonUnion(..) => {}
TyKind::ImplTrait(id, _) => {
// HACK: pprust breaks strings with newlines when the type
// gets too long. We don't want these to show up in compiler
// output or built artifacts, so replace them here...
// Perhaps we should instead format APITs more robustly.
let name = Symbol::intern(&pprust::ty_to_string(ty).replace('\n', " "));
let kind = match self.impl_trait_context {
ImplTraitContext::Universal => DefKind::TyParam,
ImplTraitContext::Existential => DefKind::OpaqueTy,
};
let id = self.create_def(*id, name, kind, ty.span);
match self.impl_trait_context {
// Do not nest APIT, as we desugar them as `impl_trait: bounds`,
// so the `impl_trait` node is not a parent to `bounds`.
ImplTraitContext::Universal => visit::walk_ty(self, ty),
ImplTraitContext::Existential => {
self.with_parent(id, |this| visit::walk_ty(this, ty))
}
};
}
_ => visit::walk_ty(self, ty), _ => visit::walk_ty(self, ty),
} }
} }

View File

@ -1010,7 +1010,7 @@ fn visit_fn(&mut self, fn_kind: FnKind<'ast>, sp: Span, fn_id: NodeId) {
this.in_func_body = previous_state; this.in_func_body = previous_state;
} }
} }
FnKind::Closure(binder, declaration, body) => { FnKind::Closure(binder, _, declaration, body) => {
this.visit_closure_binder(binder); this.visit_closure_binder(binder);
this.with_lifetime_rib( this.with_lifetime_rib(

View File

@ -3,14 +3,14 @@
field_tys: { field_tys: {
_0: CoroutineSavedTy { _0: CoroutineSavedTy {
ty: Coroutine( ty: Coroutine(
DefId(0:4 ~ async_await[ccf8]::a::{closure#0}), DefId(0:5 ~ async_await[ccf8]::a::{closure#0}),
[ [
(), (),
std::future::ResumeTy, std::future::ResumeTy,
(), (),
(), (),
CoroutineWitness( CoroutineWitness(
DefId(0:4 ~ async_await[ccf8]::a::{closure#0}), DefId(0:5 ~ async_await[ccf8]::a::{closure#0}),
[], [],
), ),
(), (),
@ -24,14 +24,14 @@
}, },
_1: CoroutineSavedTy { _1: CoroutineSavedTy {
ty: Coroutine( ty: Coroutine(
DefId(0:4 ~ async_await[ccf8]::a::{closure#0}), DefId(0:5 ~ async_await[ccf8]::a::{closure#0}),
[ [
(), (),
std::future::ResumeTy, std::future::ResumeTy,
(), (),
(), (),
CoroutineWitness( CoroutineWitness(
DefId(0:4 ~ async_await[ccf8]::a::{closure#0}), DefId(0:5 ~ async_await[ccf8]::a::{closure#0}),
[], [],
), ),
(), (),

View File

@ -10,7 +10,7 @@ note: coroutine is not `Send` as this value is used across a yield
--> $DIR/coroutine-print-verbose-1.rs:35:9 --> $DIR/coroutine-print-verbose-1.rs:35:9
| |
LL | let _non_send_gen = make_non_send_coroutine(); LL | let _non_send_gen = make_non_send_coroutine();
| ------------- has type `Opaque(DefId(0:34 ~ coroutine_print_verbose_1[75fb]::make_non_send_coroutine::{opaque#0}), [])` which is not `Send` | ------------- has type `Opaque(DefId(0:24 ~ coroutine_print_verbose_1[75fb]::make_non_send_coroutine::{opaque#0}), [])` which is not `Send`
LL | yield; LL | yield;
| ^^^^^ yield occurs here, with `_non_send_gen` maybe used later | ^^^^^ yield occurs here, with `_non_send_gen` maybe used later
note: required by a bound in `require_send` note: required by a bound in `require_send`
@ -33,12 +33,12 @@ note: required because it's used within this coroutine
| |
LL | #[coroutine] || { LL | #[coroutine] || {
| ^^ | ^^
note: required because it appears within the type `Opaque(DefId(0:35 ~ coroutine_print_verbose_1[75fb]::make_gen2::{opaque#0}), [Arc<RefCell<i32>>])` note: required because it appears within the type `Opaque(DefId(0:29 ~ coroutine_print_verbose_1[75fb]::make_gen2::{opaque#0}), [Arc<RefCell<i32>>])`
--> $DIR/coroutine-print-verbose-1.rs:41:30 --> $DIR/coroutine-print-verbose-1.rs:41:30
| |
LL | pub fn make_gen2<T>(t: T) -> impl Coroutine<Return = T> { LL | pub fn make_gen2<T>(t: T) -> impl Coroutine<Return = T> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^
note: required because it appears within the type `Opaque(DefId(0:36 ~ coroutine_print_verbose_1[75fb]::make_non_send_coroutine2::{opaque#0}), [])` note: required because it appears within the type `Opaque(DefId(0:32 ~ coroutine_print_verbose_1[75fb]::make_non_send_coroutine2::{opaque#0}), [])`
--> $DIR/coroutine-print-verbose-1.rs:47:34 --> $DIR/coroutine-print-verbose-1.rs:47:34
| |
LL | fn make_non_send_coroutine2() -> impl Coroutine<Return = Arc<RefCell<i32>>> { LL | fn make_non_send_coroutine2() -> impl Coroutine<Return = Arc<RefCell<i32>>> {

View File

@ -1,16 +1,16 @@
error[E0700]: hidden type for `Opaque(DefId(0:13 ~ impl_trait_captures[aeb9]::foo::{opaque#0}), ['a/#0, T, 'a/#0])` captures lifetime that does not appear in bounds error[E0700]: hidden type for `Opaque(DefId(0:11 ~ impl_trait_captures[aeb9]::foo::{opaque#0}), ['a/#0, T, 'a/#0])` captures lifetime that does not appear in bounds
--> $DIR/impl-trait-captures.rs:11:5 --> $DIR/impl-trait-captures.rs:11:5
| |
LL | fn foo<'a, T>(x: &T) -> impl Foo<'a> { LL | fn foo<'a, T>(x: &T) -> impl Foo<'a> {
| -- ------------ opaque type defined here | -- ------------ opaque type defined here
| | | |
| hidden type `&ReLateParam(DefId(0:8 ~ impl_trait_captures[aeb9]::foo), BrNamed(DefId(0:12 ~ impl_trait_captures[aeb9]::foo::'_), '_)) T` captures the anonymous lifetime defined here | hidden type `&ReLateParam(DefId(0:8 ~ impl_trait_captures[aeb9]::foo), BrNamed(DefId(0:13 ~ impl_trait_captures[aeb9]::foo::'_), '_)) T` captures the anonymous lifetime defined here
LL | x LL | x
| ^ | ^
| |
help: add a `use<...>` bound to explicitly capture `ReLateParam(DefId(0:8 ~ impl_trait_captures[aeb9]::foo), BrNamed(DefId(0:12 ~ impl_trait_captures[aeb9]::foo::'_), '_))` help: add a `use<...>` bound to explicitly capture `ReLateParam(DefId(0:8 ~ impl_trait_captures[aeb9]::foo), BrNamed(DefId(0:13 ~ impl_trait_captures[aeb9]::foo::'_), '_))`
| |
LL | fn foo<'a, T>(x: &T) -> impl Foo<'a> + use<'a, ReLateParam(DefId(0:8 ~ impl_trait_captures[aeb9]::foo), BrNamed(DefId(0:12 ~ impl_trait_captures[aeb9]::foo::'_), '_)), T> { LL | fn foo<'a, T>(x: &T) -> impl Foo<'a> + use<'a, ReLateParam(DefId(0:8 ~ impl_trait_captures[aeb9]::foo), BrNamed(DefId(0:13 ~ impl_trait_captures[aeb9]::foo::'_), '_)), T> {
| +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
error: aborting due to 1 previous error error: aborting due to 1 previous error