Skip to content

Commit 4f51df6

Browse files
committed
WIP
1 parent 55c04ba commit 4f51df6

File tree

6 files changed

+145
-51
lines changed

6 files changed

+145
-51
lines changed

src/librustc/hir/lowering.rs

+30-2
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,8 @@ use hir::map::{DefKey, DefPathData, Definitions};
4747
use hir::def_id::{DefId, DefIndex, DefIndexAddressSpace, CRATE_DEF_INDEX};
4848
use hir::def::{Def, PathResolution, PerNS};
4949
use hir::GenericArg;
50-
use lint::builtin::{self, PARENTHESIZED_PARAMS_IN_TYPES_AND_MODULES};
50+
use lint::builtin::{self, PARENTHESIZED_PARAMS_IN_TYPES_AND_MODULES,
51+
ELIDED_LIFETIMES_IN_PATHS};
5152
use middle::cstore::CrateStore;
5253
use rustc_data_structures::indexed_vec::IndexVec;
5354
use session::Session;
@@ -1753,13 +1754,40 @@ impl<'a> LoweringContext<'a> {
17531754
GenericArg::Lifetime(_) => true,
17541755
_ => false,
17551756
});
1757+
let first_generic_span = generic_args.args.iter().map(|a| a.span())
1758+
.chain(generic_args.bindings.iter().map(|b| b.span)).next();
17561759
if !generic_args.parenthesized && !has_lifetimes {
17571760
generic_args.args =
17581761
self.elided_path_lifetimes(path_span, expected_lifetimes)
17591762
.into_iter()
17601763
.map(|lt| GenericArg::Lifetime(lt))
17611764
.chain(generic_args.args.into_iter())
1762-
.collect();
1765+
.collect();
1766+
if expected_lifetimes > 0 && param_mode == ParamMode::Explicit {
1767+
let anon_lt_suggestion = iter::repeat("'_").collect::<Vec<_>>().join(", ");
1768+
let no_ty_args = generic_args.args.len() == expected_lifetimes;
1769+
let no_bindings = generic_args.bindings.is_empty();
1770+
let (incl_angl_brckt, insertion_span, suggestion) = if no_ty_args && no_bindings {
1771+
// If there are no (non-implicit) generic args or associated-type
1772+
// bindings, our suggestion includes the angle brackets
1773+
(true, path_span.shrink_to_hi(), format!("<{}>", anon_lt_suggestion))
1774+
} else {
1775+
// Otherwise—sorry, this is kind of gross—we need to infer the
1776+
// place to splice in the `'_, ` from the generics that do exist
1777+
let first_generic_span = first_generic_span
1778+
.expect("already checked that type args or bindings exist");
1779+
(false, first_generic_span.shrink_to_lo(), anon_lt_suggestion)
1780+
};
1781+
self.sess.buffer_lint_with_diagnostic(
1782+
ELIDED_LIFETIMES_IN_PATHS,
1783+
CRATE_NODE_ID,
1784+
path_span,
1785+
"hidden lifetime parameters are deprecated",
1786+
builtin::BuiltinLintDiagnostics::ElidedLifetimesInPaths(
1787+
expected_lifetimes, path_span, incl_angl_brckt, insertion_span, suggestion
1788+
)
1789+
);
1790+
}
17631791
}
17641792

17651793
hir::PathSegment::new(

src/librustc/lint/builtin.rs

+25
Original file line numberDiff line numberDiff line change
@@ -400,6 +400,7 @@ pub enum BuiltinLintDiagnostics {
400400
AbsPathWithModule(Span),
401401
DuplicatedMacroExports(ast::Ident, Span, Span),
402402
ProcMacroDeriveResolutionFallback(Span),
403+
ElidedLifetimesInPaths(usize, Span, bool, Span, String),
403404
}
404405

405406
impl BuiltinLintDiagnostics {
@@ -440,6 +441,30 @@ impl BuiltinLintDiagnostics {
440441
db.span_label(span, "names from parent modules are not \
441442
accessible without an explicit import");
442443
}
444+
BuiltinLintDiagnostics::ElidedLifetimesInPaths(
445+
n, path_span, incl_angl_brckt, insertion_span, anon_lts
446+
) => {
447+
let (replace_span, suggestion) = if incl_angl_brckt {
448+
(insertion_span, anon_lts)
449+
} else {
450+
// If our codemap can be trusted, construct the entire `Path<'_, T>` source
451+
// suggestion
452+
if let Ok(snippet) = sess.codemap().span_to_snippet(path_span) {
453+
let (before, after) = snippet.split_at(
454+
(insertion_span.lo().0 - path_span.lo().0) as usize
455+
);
456+
(path_span, format!("{}{}{}", before, anon_lts, after))
457+
} else {
458+
(insertion_span, anon_lts)
459+
}
460+
};
461+
db.span_suggestion_with_applicability(
462+
replace_span,
463+
&format!("indicate the anonymous lifetime{}", if n >= 2 { "s" } else { "" }),
464+
suggestion,
465+
Applicability::MachineApplicable
466+
);
467+
}
443468
}
444469
}
445470
}

src/librustc/middle/resolve_lifetime.rs

+4-16
Original file line numberDiff line numberDiff line change
@@ -609,7 +609,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
609609
// resolved the same as the `'_` in `&'_ Foo`.
610610
//
611611
// cc #48468
612-
self.resolve_elided_lifetimes(vec![lifetime], false)
612+
self.resolve_elided_lifetimes(vec![lifetime])
613613
}
614614
LifetimeName::Param(_) | LifetimeName::Static => {
615615
// If the user wrote an explicit name, use that.
@@ -857,7 +857,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
857857

858858
fn visit_lifetime(&mut self, lifetime_ref: &'tcx hir::Lifetime) {
859859
if lifetime_ref.is_elided() {
860-
self.resolve_elided_lifetimes(vec![lifetime_ref], false);
860+
self.resolve_elided_lifetimes(vec![lifetime_ref]);
861861
return;
862862
}
863863
if lifetime_ref.is_static() {
@@ -1691,7 +1691,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
16911691
_ => None,
16921692
}).collect();
16931693
if elide_lifetimes {
1694-
self.resolve_elided_lifetimes(lifetimes, true);
1694+
self.resolve_elided_lifetimes(lifetimes);
16951695
} else {
16961696
lifetimes.iter().for_each(|lt| self.visit_lifetime(lt));
16971697
}
@@ -2069,26 +2069,14 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
20692069
}
20702070

20712071
fn resolve_elided_lifetimes(&mut self,
2072-
lifetime_refs: Vec<&'tcx hir::Lifetime>,
2073-
deprecated: bool) {
2072+
lifetime_refs: Vec<&'tcx hir::Lifetime>) {
20742073
if lifetime_refs.is_empty() {
20752074
return;
20762075
}
20772076

20782077
let span = lifetime_refs[0].span;
2079-
let id = lifetime_refs[0].id;
20802078
let mut late_depth = 0;
20812079
let mut scope = self.scope;
2082-
if deprecated {
2083-
self.tcx
2084-
.struct_span_lint_node(
2085-
lint::builtin::ELIDED_LIFETIMES_IN_PATHS,
2086-
id,
2087-
span,
2088-
&format!("hidden lifetime parameters are deprecated, try `Foo<'_>`"),
2089-
)
2090-
.emit();
2091-
}
20922080
let error = loop {
20932081
match *scope {
20942082
// Do not assign any resolution, it will be inferred.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// run-rustfix
12+
// compile-flags: --edition 2018
13+
14+
#![allow(unused)]
15+
#![deny(elided_lifetimes_in_paths)]
16+
//~^ NOTE lint level defined here
17+
18+
use std::cell::{RefCell, Ref};
19+
20+
21+
struct Foo<'a> { x: &'a u32 }
22+
23+
fn foo(x: &Foo) {
24+
//~^ ERROR hidden lifetime parameters in types are deprecated
25+
//~| HELP indicate the anonymous lifetime
26+
}
27+
28+
fn bar(x: &Foo<'_>) {}
29+
30+
31+
struct Wrapped<'a>(&'a str);
32+
33+
struct WrappedWithBow<'a> {
34+
gift: &'a str
35+
}
36+
37+
fn wrap_gift(gift: &str) -> Wrapped {
38+
//~^ ERROR hidden lifetime parameters in types are deprecated
39+
//~| HELP indicate the anonymous lifetime
40+
Wrapped(gift)
41+
}
42+
43+
fn wrap_gift_with_bow(gift: &str) -> WrappedWithBow {
44+
//~^ ERROR hidden lifetime parameters in types are deprecated
45+
//~| HELP indicate the anonymous lifetime
46+
WrappedWithBow { gift }
47+
}
48+
49+
macro_rules! autowrapper {
50+
($type_name:ident, $fn_name:ident, $lt:lifetime) => {
51+
struct $type_name<$lt> {
52+
gift: &$lt str
53+
}
54+
55+
fn $fn_name(gift: &str) -> $type_name {
56+
//~^ ERROR hidden lifetime parameters in types are deprecated
57+
//~| HELP indicate the anonymous lifetime
58+
$type_name { gift }
59+
}
60+
}
61+
}
62+
63+
autowrapper!(Autowrapped, autowrap_gift, 'a);
64+
//~^ NOTE in this expansion of autowrapper!
65+
//~| NOTE in this expansion of autowrapper!
66+
67+
macro_rules! anytuple_ref_ty {
68+
($($types:ty),*) => {
69+
Ref<($($types),*)>
70+
//~^ ERROR hidden lifetime parameters in types are deprecated
71+
//~| HELP indicate the anonymous lifetime
72+
}
73+
}
74+
75+
fn main() {
76+
let honesty = RefCell::new((4, 'e'));
77+
let loyalty: Ref<(u32, char)> = honesty.borrow();
78+
//~^ ERROR hidden lifetime parameters in types are deprecated
79+
//~| HELP indicate the anonymous lifetime
80+
let generosity = Ref::map(loyalty, |t| &t.0);
81+
82+
let laughter = RefCell::new((true, "magic"));
83+
let yellow: anytuple_ref_ty!(bool, &str) = laughter.borrow();
84+
//~^ NOTE in this expansion of anytuple_ref_ty!
85+
//~| NOTE in this expansion of anytuple_ref_ty!
86+
}

src/test/ui/in-band-lifetimes/ellided-lifetimes.rs

-19
This file was deleted.

src/test/ui/in-band-lifetimes/ellided-lifetimes.stderr

-14
This file was deleted.

0 commit comments

Comments
 (0)