Auto merge of #61679 - zackmdavis:maybe_dont_indicate_the_anonymous_lifetime, r=oli-obk

in which we decline to suggest the anonymous lifetime in declarations

The elided-lifetimes-in-path lint (part of our suite of Rust 2018 idiom lints which we are hoping to promote to Warn status) was firing with an illegal suggestion to write an anonymous lifetime in a
struct/item declaration (where we don't allow it). The linting code was already deciding whether to act on the basis of a `ParamMode` enum, indicating whether the present path-segment was part of an
expression, or anywhere else. The present case seemed to be part of the "anywhere else", and yet meriting different rules as far as the lint was concerned, so it seemed expedient to introduce a new enum member. We yank out `TyKind::Path` arm into its own method so that we can call it with our new `ParamMode` specifically when lowering struct fields—one would have hoped to think of something more elegant than this, but it definitely beats changing the signature of `lower_ty` to take a `ParamMode`!

Resolves #61124.

cc @memoryruins
r? @oli-obk
This commit is contained in:
bors 2019-06-14 09:39:17 +00:00
commit e699ea096f
3 changed files with 52 additions and 8 deletions

View file

@ -274,6 +274,8 @@ pub fn lower_crate(
enum ParamMode { enum ParamMode {
/// Any path in a type context. /// Any path in a type context.
Explicit, Explicit,
/// Path in a type definition, where the anonymous lifetime `'_` is not allowed.
ExplicitNamed,
/// The `module::Type` in `module::Type::method` in an expression. /// The `module::Type` in `module::Type::method` in an expression.
Optional, Optional,
} }
@ -1489,6 +1491,23 @@ impl<'a> LoweringContext<'a> {
P(self.lower_ty_direct(t, itctx)) P(self.lower_ty_direct(t, itctx))
} }
fn lower_path_ty(
&mut self,
t: &Ty,
qself: &Option<QSelf>,
path: &Path,
param_mode: ParamMode,
itctx: ImplTraitContext<'_>
) -> hir::Ty {
let id = self.lower_node_id(t.id);
let qpath = self.lower_qpath(t.id, qself, path, param_mode, itctx);
let ty = self.ty_path(id, t.span, qpath);
if let hir::TyKind::TraitObject(..) = ty.node {
self.maybe_lint_bare_trait(t.span, t.id, qself.is_none() && path.is_global());
}
ty
}
fn lower_ty_direct(&mut self, t: &Ty, mut itctx: ImplTraitContext<'_>) -> hir::Ty { fn lower_ty_direct(&mut self, t: &Ty, mut itctx: ImplTraitContext<'_>) -> hir::Ty {
let kind = match t.node { let kind = match t.node {
TyKind::Infer => hir::TyKind::Infer, TyKind::Infer => hir::TyKind::Infer,
@ -1534,13 +1553,7 @@ impl<'a> LoweringContext<'a> {
return self.lower_ty_direct(ty, itctx); return self.lower_ty_direct(ty, itctx);
} }
TyKind::Path(ref qself, ref path) => { TyKind::Path(ref qself, ref path) => {
let id = self.lower_node_id(t.id); return self.lower_path_ty(t, qself, path, ParamMode::Explicit, itctx);
let qpath = self.lower_qpath(t.id, qself, path, ParamMode::Explicit, itctx);
let ty = self.ty_path(id, t.span, qpath);
if let hir::TyKind::TraitObject(..) = ty.node {
self.maybe_lint_bare_trait(t.span, t.id, qself.is_none() && path.is_global());
}
return ty;
} }
TyKind::ImplicitSelf => { TyKind::ImplicitSelf => {
let res = self.expect_full_res(t.id); let res = self.expect_full_res(t.id);
@ -3086,6 +3099,18 @@ impl<'a> LoweringContext<'a> {
} }
fn lower_struct_field(&mut self, (index, f): (usize, &StructField)) -> hir::StructField { fn lower_struct_field(&mut self, (index, f): (usize, &StructField)) -> hir::StructField {
let ty = if let TyKind::Path(ref qself, ref path) = f.ty.node {
let t = self.lower_path_ty(
&f.ty,
qself,
path,
ParamMode::ExplicitNamed, // no `'_` in declarations (Issue #61124)
ImplTraitContext::disallowed()
);
P(t)
} else {
self.lower_ty(&f.ty, ImplTraitContext::disallowed())
};
hir::StructField { hir::StructField {
span: f.span, span: f.span,
hir_id: self.lower_node_id(f.id), hir_id: self.lower_node_id(f.id),
@ -3095,7 +3120,7 @@ impl<'a> LoweringContext<'a> {
None => Ident::new(sym::integer(index), f.span), None => Ident::new(sym::integer(index), f.span),
}, },
vis: self.lower_visibility(&f.vis, None), vis: self.lower_visibility(&f.vis, None),
ty: self.lower_ty(&f.ty, ImplTraitContext::disallowed()), ty,
attrs: self.lower_attrs(&f.attrs), attrs: self.lower_attrs(&f.attrs),
} }
} }

View file

@ -0,0 +1,10 @@
#![deny(elided_lifetimes_in_paths)]
// Previously, the elided-lifetimes-in-path lint would fire, but we don't want
// that, because `'_` isn't legal in struct declarations.
struct Betrayal<'a> { x: &'a u8 }
struct Heartbreak(Betrayal); //~ ERROR missing lifetime specifier
fn main() {}

View file

@ -0,0 +1,9 @@
error[E0106]: missing lifetime specifier
--> $DIR/issue-61124-anon-lifetime-in-struct-declaration.rs:8:19
|
LL | struct Heartbreak(Betrayal);
| ^^^^^^^^ expected lifetime parameter
error: aborting due to previous error
For more information about this error, try `rustc --explain E0106`.