Record in HIR whether lifetime elision was succesful.

This commit is contained in:
Camille GILLOT 2022-11-06 09:33:52 +00:00
parent fb7d25e978
commit 5f5e7a8eec
7 changed files with 50 additions and 34 deletions

View File

@ -603,6 +603,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
output, output,
c_variadic: false, c_variadic: false,
implicit_self: hir::ImplicitSelfKind::None, implicit_self: hir::ImplicitSelfKind::None,
lifetime_elision_allowed: false,
}); });
// Lower the argument pattern/ident. The ident is used again in the `.await` lowering. // Lower the argument pattern/ident. The ident is used again in the `.await` lowering.
@ -907,7 +908,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
let bound_generic_params = self.lower_lifetime_binder(closure_id, generic_params); let bound_generic_params = self.lower_lifetime_binder(closure_id, generic_params);
// Lower outside new scope to preserve `is_in_loop_condition`. // Lower outside new scope to preserve `is_in_loop_condition`.
let fn_decl = self.lower_fn_decl(decl, None, fn_decl_span, FnDeclKind::Closure, None); let fn_decl = self.lower_fn_decl(decl, closure_id, fn_decl_span, FnDeclKind::Closure, None);
let c = self.arena.alloc(hir::Closure { let c = self.arena.alloc(hir::Closure {
def_id: self.local_def_id(closure_id), def_id: self.local_def_id(closure_id),
@ -1017,7 +1018,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
// have to conserve the state of being inside a loop condition for the // have to conserve the state of being inside a loop condition for the
// closure argument types. // closure argument types.
let fn_decl = let fn_decl =
self.lower_fn_decl(&outer_decl, None, fn_decl_span, FnDeclKind::Closure, None); self.lower_fn_decl(&outer_decl, closure_id, fn_decl_span, FnDeclKind::Closure, None);
let c = self.arena.alloc(hir::Closure { let c = self.arena.alloc(hir::Closure {
def_id: self.local_def_id(closure_id), def_id: self.local_def_id(closure_id),

View File

@ -274,7 +274,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
let mut itctx = ImplTraitContext::Universal; let mut itctx = ImplTraitContext::Universal;
let (generics, decl) = this.lower_generics(generics, id, &mut itctx, |this| { let (generics, decl) = this.lower_generics(generics, id, &mut itctx, |this| {
let ret_id = asyncness.opt_return_id(); let ret_id = asyncness.opt_return_id();
this.lower_fn_decl(&decl, Some(id), *fn_sig_span, FnDeclKind::Fn, ret_id) this.lower_fn_decl(&decl, id, *fn_sig_span, FnDeclKind::Fn, ret_id)
}); });
let sig = hir::FnSig { let sig = hir::FnSig {
decl, decl,
@ -659,7 +659,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
// Disallow `impl Trait` in foreign items. // Disallow `impl Trait` in foreign items.
this.lower_fn_decl( this.lower_fn_decl(
fdec, fdec,
None, i.id,
sig.span, sig.span,
FnDeclKind::ExternFn, FnDeclKind::ExternFn,
None, None,
@ -1247,7 +1247,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
let header = self.lower_fn_header(sig.header); let header = self.lower_fn_header(sig.header);
let mut itctx = ImplTraitContext::Universal; let mut itctx = ImplTraitContext::Universal;
let (generics, decl) = self.lower_generics(generics, id, &mut itctx, |this| { let (generics, decl) = self.lower_generics(generics, id, &mut itctx, |this| {
this.lower_fn_decl(&sig.decl, Some(id), sig.span, kind, is_async) this.lower_fn_decl(&sig.decl, id, sig.span, kind, is_async)
}); });
(generics, hir::FnSig { header, decl, span: self.lower_span(sig.span) }) (generics, hir::FnSig { header, decl, span: self.lower_span(sig.span) })
} }

View File

@ -327,7 +327,14 @@ enum FnDeclKind {
} }
impl FnDeclKind { impl FnDeclKind {
fn impl_trait_allowed(&self, tcx: TyCtxt<'_>) -> bool { fn param_impl_trait_allowed(&self) -> bool {
match self {
FnDeclKind::Fn | FnDeclKind::Inherent | FnDeclKind::Impl | FnDeclKind::Trait => true,
_ => false,
}
}
fn return_impl_trait_allowed(&self, tcx: TyCtxt<'_>) -> bool {
match self { match self {
FnDeclKind::Fn | FnDeclKind::Inherent => true, FnDeclKind::Fn | FnDeclKind::Inherent => true,
FnDeclKind::Impl if tcx.features().return_position_impl_trait_in_trait => true, FnDeclKind::Impl if tcx.features().return_position_impl_trait_in_trait => true,
@ -1267,7 +1274,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
generic_params, generic_params,
unsafety: self.lower_unsafety(f.unsafety), unsafety: self.lower_unsafety(f.unsafety),
abi: self.lower_extern(f.ext), abi: self.lower_extern(f.ext),
decl: self.lower_fn_decl(&f.decl, None, t.span, FnDeclKind::Pointer, None), decl: self.lower_fn_decl(&f.decl, t.id, t.span, FnDeclKind::Pointer, None),
param_names: self.lower_fn_params_to_names(&f.decl), param_names: self.lower_fn_params_to_names(&f.decl),
})) }))
} }
@ -1671,7 +1678,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
fn lower_fn_decl( fn lower_fn_decl(
&mut self, &mut self,
decl: &FnDecl, decl: &FnDecl,
fn_node_id: Option<NodeId>, fn_node_id: NodeId,
fn_span: Span, fn_span: Span,
kind: FnDeclKind, kind: FnDeclKind,
make_ret_async: Option<(NodeId, Span)>, make_ret_async: Option<(NodeId, Span)>,
@ -1686,23 +1693,21 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
inputs = &inputs[..inputs.len() - 1]; inputs = &inputs[..inputs.len() - 1];
} }
let inputs = self.arena.alloc_from_iter(inputs.iter().map(|param| { let inputs = self.arena.alloc_from_iter(inputs.iter().map(|param| {
if fn_node_id.is_some() { let itctx = if kind.param_impl_trait_allowed() {
self.lower_ty_direct(&param.ty, &ImplTraitContext::Universal) ImplTraitContext::Universal
} else { } else {
self.lower_ty_direct( ImplTraitContext::Disallowed(match kind {
&param.ty, FnDeclKind::Fn | FnDeclKind::Inherent => {
&ImplTraitContext::Disallowed(match kind { unreachable!("fn should allow APIT")
FnDeclKind::Fn | FnDeclKind::Inherent => { }
unreachable!("fn should allow in-band lifetimes") FnDeclKind::ExternFn => ImplTraitPosition::ExternFnParam,
} FnDeclKind::Closure => ImplTraitPosition::ClosureParam,
FnDeclKind::ExternFn => ImplTraitPosition::ExternFnParam, FnDeclKind::Pointer => ImplTraitPosition::PointerParam,
FnDeclKind::Closure => ImplTraitPosition::ClosureParam, FnDeclKind::Trait => ImplTraitPosition::TraitParam,
FnDeclKind::Pointer => ImplTraitPosition::PointerParam, FnDeclKind::Impl => ImplTraitPosition::ImplParam,
FnDeclKind::Trait => ImplTraitPosition::TraitParam, })
FnDeclKind::Impl => ImplTraitPosition::ImplParam, };
}), self.lower_ty_direct(&param.ty, &itctx)
)
}
})); }));
let output = if let Some((ret_id, span)) = make_ret_async { let output = if let Some((ret_id, span)) = make_ret_async {
@ -1725,22 +1730,21 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
self.lower_async_fn_ret_ty( self.lower_async_fn_ret_ty(
&decl.output, &decl.output,
fn_node_id.expect("`make_ret_async` but no `fn_def_id`"), fn_node_id,
ret_id, ret_id,
matches!(kind, FnDeclKind::Trait), matches!(kind, FnDeclKind::Trait),
) )
} else { } else {
match &decl.output { match &decl.output {
FnRetTy::Ty(ty) => { FnRetTy::Ty(ty) => {
let mut context = match fn_node_id { let mut context = if kind.return_impl_trait_allowed(self.tcx) {
Some(fn_node_id) if kind.impl_trait_allowed(self.tcx) => { let fn_def_id = self.local_def_id(fn_node_id);
let fn_def_id = self.local_def_id(fn_node_id); ImplTraitContext::ReturnPositionOpaqueTy {
ImplTraitContext::ReturnPositionOpaqueTy { origin: hir::OpaqueTyOrigin::FnReturn(fn_def_id),
origin: hir::OpaqueTyOrigin::FnReturn(fn_def_id), in_trait: matches!(kind, FnDeclKind::Trait),
in_trait: matches!(kind, FnDeclKind::Trait),
}
} }
_ => ImplTraitContext::Disallowed(match kind { } else {
ImplTraitContext::Disallowed(match kind {
FnDeclKind::Fn | FnDeclKind::Inherent => { FnDeclKind::Fn | FnDeclKind::Inherent => {
unreachable!("fn should allow in-band lifetimes") unreachable!("fn should allow in-band lifetimes")
} }
@ -1749,7 +1753,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
FnDeclKind::Pointer => ImplTraitPosition::PointerReturn, FnDeclKind::Pointer => ImplTraitPosition::PointerReturn,
FnDeclKind::Trait => ImplTraitPosition::TraitReturn, FnDeclKind::Trait => ImplTraitPosition::TraitReturn,
FnDeclKind::Impl => ImplTraitPosition::ImplReturn, FnDeclKind::Impl => ImplTraitPosition::ImplReturn,
}), })
}; };
hir::FnRetTy::Return(self.lower_ty(ty, &mut context)) hir::FnRetTy::Return(self.lower_ty(ty, &mut context))
} }
@ -1761,6 +1765,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
inputs, inputs,
output, output,
c_variadic, c_variadic,
lifetime_elision_allowed: self.resolver.lifetime_elision_allowed.contains(&fn_node_id),
implicit_self: decl.inputs.get(0).map_or(hir::ImplicitSelfKind::None, |arg| { implicit_self: decl.inputs.get(0).map_or(hir::ImplicitSelfKind::None, |arg| {
let is_mutable_pat = matches!( let is_mutable_pat = matches!(
arg.pat.kind, arg.pat.kind,

View File

@ -2670,6 +2670,8 @@ pub struct FnDecl<'hir> {
pub c_variadic: bool, pub c_variadic: bool,
/// Does the function have an implicit self? /// Does the function have an implicit self?
pub implicit_self: ImplicitSelfKind, pub implicit_self: ImplicitSelfKind,
/// Is lifetime elision allowed.
pub lifetime_elision_allowed: bool,
} }
/// Represents what type of implicit self a function has, if any. /// Represents what type of implicit self a function has, if any.

View File

@ -207,6 +207,8 @@ pub struct ResolverAstLowering {
/// A small map keeping true kinds of built-in macros that appear to be fn-like on /// A small map keeping true kinds of built-in macros that appear to be fn-like on
/// the surface (`macro` items in libcore), but are actually attributes or derives. /// the surface (`macro` items in libcore), but are actually attributes or derives.
pub builtin_macro_kinds: FxHashMap<LocalDefId, MacroKind>, pub builtin_macro_kinds: FxHashMap<LocalDefId, MacroKind>,
/// List functions and methods for which lifetime elision was successful.
pub lifetime_elision_allowed: FxHashSet<ast::NodeId>,
} }
#[derive(Clone, Copy, Debug)] #[derive(Clone, Copy, Debug)]

View File

@ -1838,6 +1838,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
let outer_failures = take(&mut self.diagnostic_metadata.current_elision_failures); let outer_failures = take(&mut self.diagnostic_metadata.current_elision_failures);
let output_rib = if let Ok(res) = elision_lifetime.as_ref() { let output_rib = if let Ok(res) = elision_lifetime.as_ref() {
self.r.lifetime_elision_allowed.insert(fn_id);
LifetimeRibKind::Elided(*res) LifetimeRibKind::Elided(*res)
} else { } else {
LifetimeRibKind::ElisionFailure LifetimeRibKind::ElisionFailure

View File

@ -1036,6 +1036,8 @@ pub struct Resolver<'a> {
/// they are declared in the static array generated by proc_macro_harness. /// they are declared in the static array generated by proc_macro_harness.
proc_macros: Vec<NodeId>, proc_macros: Vec<NodeId>,
confused_type_with_std_module: FxHashMap<Span, Span>, confused_type_with_std_module: FxHashMap<Span, Span>,
/// Whether lifetime elision was successful.
lifetime_elision_allowed: FxHashSet<NodeId>,
effective_visibilities: EffectiveVisibilities, effective_visibilities: EffectiveVisibilities,
} }
@ -1354,6 +1356,7 @@ impl<'a> Resolver<'a> {
trait_impls: Default::default(), trait_impls: Default::default(),
proc_macros: Default::default(), proc_macros: Default::default(),
confused_type_with_std_module: Default::default(), confused_type_with_std_module: Default::default(),
lifetime_elision_allowed: Default::default(),
effective_visibilities: Default::default(), effective_visibilities: Default::default(),
}; };
@ -1448,6 +1451,7 @@ impl<'a> Resolver<'a> {
def_id_to_node_id: self.def_id_to_node_id, def_id_to_node_id: self.def_id_to_node_id,
trait_map: self.trait_map, trait_map: self.trait_map,
builtin_macro_kinds: self.builtin_macro_kinds, builtin_macro_kinds: self.builtin_macro_kinds,
lifetime_elision_allowed: self.lifetime_elision_allowed,
}; };
ResolverOutputs { definitions, global_ctxt, ast_lowering } ResolverOutputs { definitions, global_ctxt, ast_lowering }
} }
@ -1491,6 +1495,7 @@ impl<'a> Resolver<'a> {
def_id_to_node_id: self.def_id_to_node_id.clone(), def_id_to_node_id: self.def_id_to_node_id.clone(),
trait_map: self.trait_map.clone(), trait_map: self.trait_map.clone(),
builtin_macro_kinds: self.builtin_macro_kinds.clone(), builtin_macro_kinds: self.builtin_macro_kinds.clone(),
lifetime_elision_allowed: self.lifetime_elision_allowed.clone(),
}; };
ResolverOutputs { definitions, global_ctxt, ast_lowering } ResolverOutputs { definitions, global_ctxt, ast_lowering }
} }