about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2022-07-11 17:09:37 +0000
committerbors <bors@rust-lang.org>2022-07-11 17:09:37 +0000
commit38b72154ded23847cd08a796d0c6708b5efac265 (patch)
tree6250bc421ddfbb5a6e85c2e4bdb5a4cb28b24b73
parent9fb32dc924653e35950f17c8d91793c9ca983d03 (diff)
parent21a12e8ab78f7e67a4ddc1d13d289a496f2f619d (diff)
downloadrust-38b72154ded23847cd08a796d0c6708b5efac265.tar.gz
rust-38b72154ded23847cd08a796d0c6708b5efac265.zip
Auto merge of #98637 - cjgillot:bare-trait-anon-lt, r=petrochenkov
Create fresh lifetime parameters for bare fn trait too

The current code fails to account for the equivalence between `dyn FnMut(&mut u8)` and bare `FnMut(&mut u8)`, and treated them differently.

This PR introduces a special case for `Fn` traits, which are always fully resolved.

Fixes #98616
Fixes #98726
This will require a beta-backport, as beta contains that bug.

r? `@petrochenkov`
-rw-r--r--compiler/rustc_ast_lowering/src/lib.rs27
-rw-r--r--compiler/rustc_resolve/src/late.rs24
-rw-r--r--src/test/ui/lifetimes/bare-trait-object-borrowck.rs24
-rw-r--r--src/test/ui/lifetimes/bare-trait-object.rs25
4 files changed, 100 insertions, 0 deletions
diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs
index 2dcbd0782ef..fdf60e60914 100644
--- a/compiler/rustc_ast_lowering/src/lib.rs
+++ b/compiler/rustc_ast_lowering/src/lib.rs
@@ -1159,6 +1159,33 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         param_mode: ParamMode,
         itctx: ImplTraitContext,
     ) -> hir::Ty<'hir> {
+        // Check whether we should interpret this as a bare trait object.
+        // This check mirrors the one in late resolution.  We only introduce this special case in
+        // the rare occurence we need to lower `Fresh` anonymous lifetimes.
+        // The other cases when a qpath should be opportunistically made a trait object are handled
+        // by `ty_path`.
+        if qself.is_none()
+            && let Some(partial_res) = self.resolver.get_partial_res(t.id)
+            && partial_res.unresolved_segments() == 0
+            && let Res::Def(DefKind::Trait | DefKind::TraitAlias, _) = partial_res.base_res()
+        {
+            let (bounds, lifetime_bound) = self.with_dyn_type_scope(true, |this| {
+                let bound = this.lower_poly_trait_ref(
+                    &PolyTraitRef {
+                        bound_generic_params: vec![],
+                        trait_ref: TraitRef { path: path.clone(), ref_id: t.id },
+                        span: t.span
+                    },
+                    itctx,
+                );
+                let bounds = this.arena.alloc_from_iter([bound]);
+                let lifetime_bound = this.elided_dyn_bound(t.span);
+                (bounds, lifetime_bound)
+            });
+            let kind = hir::TyKind::TraitObject(bounds, lifetime_bound, TraitObjectSyntax::None);
+            return hir::Ty { kind, span: self.lower_span(t.span), hir_id: self.next_id() };
+        }
+
         let id = self.lower_node_id(t.id);
         let qpath = self.lower_qpath(t.id, qself, path, param_mode, itctx);
         self.ty_path(id, t.span, qpath)
diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs
index f37acca3d9f..098b5a0c92e 100644
--- a/compiler/rustc_resolve/src/late.rs
+++ b/compiler/rustc_resolve/src/late.rs
@@ -611,6 +611,30 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> {
             TyKind::Path(ref qself, ref path) => {
                 self.diagnostic_metadata.current_type_path = Some(ty);
                 self.smart_resolve_path(ty.id, qself.as_ref(), path, PathSource::Type);
+
+                // Check whether we should interpret this as a bare trait object.
+                if qself.is_none()
+                    && let Some(partial_res) = self.r.partial_res_map.get(&ty.id)
+                    && partial_res.unresolved_segments() == 0
+                    && let Res::Def(DefKind::Trait | DefKind::TraitAlias, _) = partial_res.base_res()
+                {
+                    // This path is actually a bare trait object.  In case of a bare `Fn`-trait
+                    // object with anonymous lifetimes, we need this rib to correctly place the
+                    // synthetic lifetimes.
+                    let span = ty.span.shrink_to_lo().to(path.span.shrink_to_lo());
+                    self.with_generic_param_rib(
+                        &[],
+                        NormalRibKind,
+                        LifetimeRibKind::Generics {
+                            binder: ty.id,
+                            kind: LifetimeBinderKind::PolyTrait,
+                            span,
+                        },
+                        |this| this.visit_path(&path, ty.id),
+                    );
+                    self.diagnostic_metadata.current_type_path = prev_ty;
+                    return;
+                }
             }
             TyKind::ImplicitSelf => {
                 let self_ty = Ident::with_dummy_span(kw::SelfUpper);
diff --git a/src/test/ui/lifetimes/bare-trait-object-borrowck.rs b/src/test/ui/lifetimes/bare-trait-object-borrowck.rs
new file mode 100644
index 00000000000..45f5e4ae129
--- /dev/null
+++ b/src/test/ui/lifetimes/bare-trait-object-borrowck.rs
@@ -0,0 +1,24 @@
+#![allow(bare_trait_objects)]
+// check-pass
+pub struct FormatWith<'a, I, F> {
+    sep: &'a str,
+    /// FormatWith uses interior mutability because Display::fmt takes &self.
+    inner: RefCell<Option<(I, F)>>,
+}
+
+use std::cell::RefCell;
+use std::fmt;
+
+struct Layout;
+
+pub fn new_format<'a, I, F>(iter: I, separator: &'a str, f: F) -> FormatWith<'a, I, F>
+where
+    I: Iterator,
+    F: FnMut(I::Item, &mut FnMut(&fmt::Display) -> fmt::Result) -> fmt::Result,
+{
+    FormatWith { sep: separator, inner: RefCell::new(Some((iter, f))) }
+}
+
+fn main() {
+    let _ = new_format(0..32, " | ", |i, f| f(&format_args!("0x{:x}", i)));
+}
diff --git a/src/test/ui/lifetimes/bare-trait-object.rs b/src/test/ui/lifetimes/bare-trait-object.rs
new file mode 100644
index 00000000000..9eff618c734
--- /dev/null
+++ b/src/test/ui/lifetimes/bare-trait-object.rs
@@ -0,0 +1,25 @@
+// Verify that lifetime resolution correctly accounts for `Fn` bare trait objects.
+// check-pass
+#![allow(bare_trait_objects)]
+
+// This should work as: fn next_u32(fill_buf: &mut dyn FnMut(&mut [u8]))
+fn next_u32(fill_buf: &mut FnMut(&mut [u8])) {
+    let mut buf: [u8; 4] = [0; 4];
+    fill_buf(&mut buf);
+}
+
+fn explicit(fill_buf: &mut dyn FnMut(&mut [u8])) {
+    let mut buf: [u8; 4] = [0; 4];
+    fill_buf(&mut buf);
+}
+
+fn main() {
+    let _: fn(&mut FnMut(&mut [u8])) = next_u32;
+    let _: &dyn Fn(&mut FnMut(&mut [u8])) = &next_u32;
+    let _: fn(&mut FnMut(&mut [u8])) = explicit;
+    let _: &dyn Fn(&mut FnMut(&mut [u8])) = &explicit;
+    let _: fn(&mut dyn FnMut(&mut [u8])) = next_u32;
+    let _: &dyn Fn(&mut dyn FnMut(&mut [u8])) = &next_u32;
+    let _: fn(&mut dyn FnMut(&mut [u8])) = explicit;
+    let _: &dyn Fn(&mut dyn FnMut(&mut [u8])) = &explicit;
+}