diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 2dcbd0782ef72..fdf60e60914a4 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 f37acca3d9f27..098b5a0c92e9b 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 0000000000000..45f5e4ae129a1 --- /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>, +} + +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 0000000000000..9eff618c734d5 --- /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; +}