Don't give APITs names with macro expansion placeholder fragments in it

This commit is contained in:
Michael Goulet 2025-06-18 17:57:22 +00:00
parent 2801f9aaf9
commit 8cd3fa04e2
9 changed files with 77 additions and 18 deletions

View file

@ -1118,6 +1118,10 @@ pub trait ResolverExpand {
trait_def_id: DefId,
impl_def_id: LocalDefId,
) -> Result<Vec<(Ident, Option<Ident>)>, Indeterminate>;
/// Record the name of an opaque `Ty::ImplTrait` pre-expansion so that it can be used
/// to generate an item name later that does not reference placeholder macros.
fn insert_impl_trait_name(&mut self, id: NodeId, name: Symbol);
}
pub trait LintStoreExpand {

View file

@ -1778,6 +1778,16 @@ impl InvocationCollectorNode for ast::Ty {
fragment.make_ty()
}
fn walk(&mut self, collector: &mut InvocationCollector<'_, '_>) {
// Save the pre-expanded name of this `ImplTrait`, so that later when defining
// an APIT we use a name that doesn't have any placeholder fragments in it.
if let ast::TyKind::ImplTrait(..) = self.kind {
// 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(self).replace('\n', " "));
collector.cx.resolver.insert_impl_trait_name(self.id, name);
}
walk_ty(collector, self)
}
fn is_mac_call(&self) -> bool {

View file

@ -2,12 +2,12 @@ use std::mem;
use rustc_ast::visit::FnKind;
use rustc_ast::*;
use rustc_ast_pretty::pprust;
use rustc_attr_parsing::{AttributeParser, Early, OmitDoc};
use rustc_expand::expand::AstFragment;
use rustc_hir as hir;
use rustc_hir::def::{CtorKind, CtorOf, DefKind};
use rustc_hir::def_id::LocalDefId;
use rustc_middle::span_bug;
use rustc_span::hygiene::LocalExpnId;
use rustc_span::{Span, Symbol, sym};
use tracing::debug;
@ -380,20 +380,20 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> {
}
fn visit_ty(&mut self, ty: &'a Ty) {
match &ty.kind {
match ty.kind {
TyKind::MacCall(..) => self.visit_macro_invoc(ty.id),
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', " "));
TyKind::ImplTrait(opaque_id, _) => {
let name = *self
.resolver
.impl_trait_names
.get(&ty.id)
.unwrap_or_else(|| span_bug!(ty.span, "expected this opaque to be named"));
let kind = match self.invocation_parent.impl_trait_context {
ImplTraitContext::Universal => DefKind::TyParam,
ImplTraitContext::Existential => DefKind::OpaqueTy,
ImplTraitContext::InBinding => return visit::walk_ty(self, ty),
};
let id = self.create_def(*id, Some(name), kind, ty.span);
let id = self.create_def(opaque_id, Some(name), kind, ty.span);
match self.invocation_parent.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`.

View file

@ -1224,6 +1224,11 @@ pub struct Resolver<'ra, 'tcx> {
current_crate_outer_attr_insert_span: Span,
mods_with_parse_errors: FxHashSet<DefId>,
// Stores pre-expansion and pre-placeholder-fragment-insertion names for `impl Trait` types
// that were encountered during resolution. These names are used to generate item names
// for APITs, so we don't want to leak details of resolution into these names.
impl_trait_names: FxHashMap<NodeId, Symbol>,
}
/// This provides memory for the rest of the crate. The `'ra` lifetime that is
@ -1579,6 +1584,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
impl_binding_keys: Default::default(),
current_crate_outer_attr_insert_span,
mods_with_parse_errors: Default::default(),
impl_trait_names: Default::default(),
};
let root_parent_scope = ParentScope::module(graph_root, &resolver);

View file

@ -522,6 +522,10 @@ impl<'ra, 'tcx> ResolverExpand for Resolver<'ra, 'tcx> {
});
Ok(idents)
}
fn insert_impl_trait_name(&mut self, id: NodeId, name: Symbol) {
self.impl_trait_names.insert(id, name);
}
}
impl<'ra, 'tcx> Resolver<'ra, 'tcx> {

View file

@ -1,9 +0,0 @@
//@ known-bug: #140333
fn a() -> impl b<
[c; {
struct d {
#[a]
bar: e,
}
}],
>;

View file

@ -0,0 +1,12 @@
trait Foo<T> {}
macro_rules! bar {
() => { () }
}
fn foo(x: impl Foo<bar!()>) {
let () = x;
//~^ ERROR mismatched types
}
fn main() {}

View file

@ -0,0 +1,16 @@
error[E0308]: mismatched types
--> $DIR/name-mentioning-macro.rs:8:9
|
LL | fn foo(x: impl Foo<bar!()>) {
| ---------------- expected this type parameter
LL | let () = x;
| ^^ - this expression has type `impl Foo<bar!()>`
| |
| expected type parameter `impl Foo<bar!()>`, found `()`
|
= note: expected type parameter `impl Foo<bar!()>`
found unit type `()`
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0308`.

View file

@ -0,0 +1,16 @@
//@ check-pass
trait Trait<T> {}
fn a(_: impl Trait<
[(); {
struct D {
#[rustfmt::skip]
bar: (),
}
0
}],
>) {
}
fn main() {}