Skip to content

Commit

Permalink
Handle fresh lifetimes on bare trait objects.
Browse files Browse the repository at this point in the history
  • Loading branch information
cjgillot authored and Mark-Simulacrum committed Jul 15, 2022
1 parent 7c2b316 commit f0227e8
Show file tree
Hide file tree
Showing 6 changed files with 53 additions and 71 deletions.
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
5 changes: 1 addition & 4 deletions src/test/ui/lifetimes/bare-trait-object-borrowck.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#![allow(bare_trait_objects)]

// check-pass
pub struct FormatWith<'a, I, F> {
sep: &'a str,
/// FormatWith uses interior mutability because Display::fmt takes &self.
Expand All @@ -21,7 +21,4 @@ where

fn main() {
let _ = new_format(0..32, " | ", |i, f| f(&format_args!("0x{:x}", i)));
//~^ ERROR temporary value dropped while borrowed
//~| ERROR temporary value dropped while borrowed
//~| ERROR `i` does not live long enough
}
43 changes: 0 additions & 43 deletions src/test/ui/lifetimes/bare-trait-object-borrowck.stderr

This file was deleted.

4 changes: 1 addition & 3 deletions src/test/ui/lifetimes/bare-trait-object.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// 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]))
Expand All @@ -15,10 +15,8 @@ fn explicit(fill_buf: &mut dyn FnMut(&mut [u8])) {

fn main() {
let _: fn(&mut FnMut(&mut [u8])) = next_u32;
//~^ ERROR mismatched types
let _: &dyn Fn(&mut FnMut(&mut [u8])) = &next_u32;
let _: fn(&mut FnMut(&mut [u8])) = explicit;
//~^ ERROR mismatched types
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;
Expand Down
21 changes: 0 additions & 21 deletions src/test/ui/lifetimes/bare-trait-object.stderr

This file was deleted.

0 comments on commit f0227e8

Please sign in to comment.