diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs index 7a29f8c9fbdef..fe76d9e0b64ed 100644 --- a/compiler/rustc_expand/src/base.rs +++ b/compiler/rustc_expand/src/base.rs @@ -1118,6 +1118,10 @@ pub trait ResolverExpand { trait_def_id: DefId, impl_def_id: LocalDefId, ) -> Result)>, 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 { diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs index 0474413e76265..2de09aa1a2802 100644 --- a/compiler/rustc_expand/src/expand.rs +++ b/compiler/rustc_expand/src/expand.rs @@ -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 { diff --git a/compiler/rustc_resolve/src/def_collector.rs b/compiler/rustc_resolve/src/def_collector.rs index 16852d1661eb4..1e345b11c1466 100644 --- a/compiler/rustc_resolve/src/def_collector.rs +++ b/compiler/rustc_resolve/src/def_collector.rs @@ -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`. diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index f0540725416cb..05bc3611dd873 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -1224,6 +1224,11 @@ pub struct Resolver<'ra, 'tcx> { current_crate_outer_attr_insert_span: Span, mods_with_parse_errors: FxHashSet, + + // 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, } /// 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); diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs index 1b82e9c97992f..3d33a02a9c6da 100644 --- a/compiler/rustc_resolve/src/macros.rs +++ b/compiler/rustc_resolve/src/macros.rs @@ -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> { diff --git a/tests/crashes/140333.rs b/tests/crashes/140333.rs deleted file mode 100644 index cec1100e6adad..0000000000000 --- a/tests/crashes/140333.rs +++ /dev/null @@ -1,9 +0,0 @@ -//@ known-bug: #140333 -fn a() -> impl b< - [c; { - struct d { - #[a] - bar: e, - } - }], ->; diff --git a/tests/ui/impl-trait/name-mentioning-macro.rs b/tests/ui/impl-trait/name-mentioning-macro.rs new file mode 100644 index 0000000000000..8a81911c0bbdf --- /dev/null +++ b/tests/ui/impl-trait/name-mentioning-macro.rs @@ -0,0 +1,12 @@ +trait Foo {} + +macro_rules! bar { + () => { () } +} + +fn foo(x: impl Foo) { + let () = x; + //~^ ERROR mismatched types +} + +fn main() {} diff --git a/tests/ui/impl-trait/name-mentioning-macro.stderr b/tests/ui/impl-trait/name-mentioning-macro.stderr new file mode 100644 index 0000000000000..adb4c64f812f1 --- /dev/null +++ b/tests/ui/impl-trait/name-mentioning-macro.stderr @@ -0,0 +1,16 @@ +error[E0308]: mismatched types + --> $DIR/name-mentioning-macro.rs:8:9 + | +LL | fn foo(x: impl Foo) { + | ---------------- expected this type parameter +LL | let () = x; + | ^^ - this expression has type `impl Foo` + | | + | expected type parameter `impl Foo`, found `()` + | + = note: expected type parameter `impl Foo` + found unit type `()` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/impl-trait/struct-field-fragment-in-name.rs b/tests/ui/impl-trait/struct-field-fragment-in-name.rs new file mode 100644 index 0000000000000..b98cd864ccb46 --- /dev/null +++ b/tests/ui/impl-trait/struct-field-fragment-in-name.rs @@ -0,0 +1,16 @@ +//@ check-pass + +trait Trait {} + +fn a(_: impl Trait< + [(); { + struct D { + #[rustfmt::skip] + bar: (), + } + 0 + }], +>) { +} + +fn main() {}