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`
This commit is contained in:
commit
38b72154de
4 changed files with 100 additions and 0 deletions
|
@ -1159,6 +1159,33 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||||
param_mode: ParamMode,
|
param_mode: ParamMode,
|
||||||
itctx: ImplTraitContext,
|
itctx: ImplTraitContext,
|
||||||
) -> hir::Ty<'hir> {
|
) -> 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 id = self.lower_node_id(t.id);
|
||||||
let qpath = self.lower_qpath(t.id, qself, path, param_mode, itctx);
|
let qpath = self.lower_qpath(t.id, qself, path, param_mode, itctx);
|
||||||
self.ty_path(id, t.span, qpath)
|
self.ty_path(id, t.span, qpath)
|
||||||
|
|
|
@ -611,6 +611,30 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> {
|
||||||
TyKind::Path(ref qself, ref path) => {
|
TyKind::Path(ref qself, ref path) => {
|
||||||
self.diagnostic_metadata.current_type_path = Some(ty);
|
self.diagnostic_metadata.current_type_path = Some(ty);
|
||||||
self.smart_resolve_path(ty.id, qself.as_ref(), path, PathSource::Type);
|
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 => {
|
TyKind::ImplicitSelf => {
|
||||||
let self_ty = Ident::with_dummy_span(kw::SelfUpper);
|
let self_ty = Ident::with_dummy_span(kw::SelfUpper);
|
||||||
|
|
24
src/test/ui/lifetimes/bare-trait-object-borrowck.rs
Normal file
24
src/test/ui/lifetimes/bare-trait-object-borrowck.rs
Normal file
|
@ -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
src/test/ui/lifetimes/bare-trait-object.rs
Normal file
25
src/test/ui/lifetimes/bare-trait-object.rs
Normal file
|
@ -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;
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue