Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Create fresh lifetime parameters for bare fn trait too #98637

Merged
merged 2 commits into from
Jul 11, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions compiler/rustc_ast_lowering/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1174,6 +1174,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)
Expand Down
24 changes: 24 additions & 0 deletions compiler/rustc_resolve/src/late.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
24 changes: 24 additions & 0 deletions src/test/ui/lifetimes/bare-trait-object-borrowck.rs
Original file line number Diff line number Diff line change
@@ -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)));
}
25 changes: 25 additions & 0 deletions src/test/ui/lifetimes/bare-trait-object.rs
Original file line number Diff line number Diff line change
@@ -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;
}