Skip to content

Commit

Permalink
WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
zackmdavis committed Jul 17, 2018
1 parent 55c04ba commit 4f51df6
Show file tree
Hide file tree
Showing 6 changed files with 145 additions and 51 deletions.
32 changes: 30 additions & 2 deletions src/librustc/hir/lowering.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,8 @@ use hir::map::{DefKey, DefPathData, Definitions};
use hir::def_id::{DefId, DefIndex, DefIndexAddressSpace, CRATE_DEF_INDEX};
use hir::def::{Def, PathResolution, PerNS};
use hir::GenericArg;
use lint::builtin::{self, PARENTHESIZED_PARAMS_IN_TYPES_AND_MODULES};
use lint::builtin::{self, PARENTHESIZED_PARAMS_IN_TYPES_AND_MODULES,
ELIDED_LIFETIMES_IN_PATHS};
use middle::cstore::CrateStore;
use rustc_data_structures::indexed_vec::IndexVec;
use session::Session;
Expand Down Expand Up @@ -1753,13 +1754,40 @@ impl<'a> LoweringContext<'a> {
GenericArg::Lifetime(_) => true,
_ => false,
});
let first_generic_span = generic_args.args.iter().map(|a| a.span())
.chain(generic_args.bindings.iter().map(|b| b.span)).next();
if !generic_args.parenthesized && !has_lifetimes {
generic_args.args =
self.elided_path_lifetimes(path_span, expected_lifetimes)
.into_iter()
.map(|lt| GenericArg::Lifetime(lt))
.chain(generic_args.args.into_iter())
.collect();
.collect();
if expected_lifetimes > 0 && param_mode == ParamMode::Explicit {
let anon_lt_suggestion = iter::repeat("'_").collect::<Vec<_>>().join(", ");
let no_ty_args = generic_args.args.len() == expected_lifetimes;
let no_bindings = generic_args.bindings.is_empty();
let (incl_angl_brckt, insertion_span, suggestion) = if no_ty_args && no_bindings {
// If there are no (non-implicit) generic args or associated-type
// bindings, our suggestion includes the angle brackets
(true, path_span.shrink_to_hi(), format!("<{}>", anon_lt_suggestion))
} else {
// Otherwise—sorry, this is kind of gross—we need to infer the
// place to splice in the `'_, ` from the generics that do exist
let first_generic_span = first_generic_span
.expect("already checked that type args or bindings exist");
(false, first_generic_span.shrink_to_lo(), anon_lt_suggestion)
};
self.sess.buffer_lint_with_diagnostic(
ELIDED_LIFETIMES_IN_PATHS,
CRATE_NODE_ID,
path_span,
"hidden lifetime parameters are deprecated",
builtin::BuiltinLintDiagnostics::ElidedLifetimesInPaths(
expected_lifetimes, path_span, incl_angl_brckt, insertion_span, suggestion
)
);
}
}

hir::PathSegment::new(
Expand Down
25 changes: 25 additions & 0 deletions src/librustc/lint/builtin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -400,6 +400,7 @@ pub enum BuiltinLintDiagnostics {
AbsPathWithModule(Span),
DuplicatedMacroExports(ast::Ident, Span, Span),
ProcMacroDeriveResolutionFallback(Span),
ElidedLifetimesInPaths(usize, Span, bool, Span, String),
}

impl BuiltinLintDiagnostics {
Expand Down Expand Up @@ -440,6 +441,30 @@ impl BuiltinLintDiagnostics {
db.span_label(span, "names from parent modules are not \
accessible without an explicit import");
}
BuiltinLintDiagnostics::ElidedLifetimesInPaths(
n, path_span, incl_angl_brckt, insertion_span, anon_lts
) => {
let (replace_span, suggestion) = if incl_angl_brckt {
(insertion_span, anon_lts)
} else {
// If our codemap can be trusted, construct the entire `Path<'_, T>` source
// suggestion
if let Ok(snippet) = sess.codemap().span_to_snippet(path_span) {
let (before, after) = snippet.split_at(
(insertion_span.lo().0 - path_span.lo().0) as usize
);
(path_span, format!("{}{}{}", before, anon_lts, after))
} else {
(insertion_span, anon_lts)
}
};
db.span_suggestion_with_applicability(
replace_span,
&format!("indicate the anonymous lifetime{}", if n >= 2 { "s" } else { "" }),
suggestion,
Applicability::MachineApplicable
);
}
}
}
}
Expand Down
20 changes: 4 additions & 16 deletions src/librustc/middle/resolve_lifetime.rs
Original file line number Diff line number Diff line change
Expand Up @@ -609,7 +609,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
// resolved the same as the `'_` in `&'_ Foo`.
//
// cc #48468
self.resolve_elided_lifetimes(vec![lifetime], false)
self.resolve_elided_lifetimes(vec![lifetime])
}
LifetimeName::Param(_) | LifetimeName::Static => {
// If the user wrote an explicit name, use that.
Expand Down Expand Up @@ -857,7 +857,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {

fn visit_lifetime(&mut self, lifetime_ref: &'tcx hir::Lifetime) {
if lifetime_ref.is_elided() {
self.resolve_elided_lifetimes(vec![lifetime_ref], false);
self.resolve_elided_lifetimes(vec![lifetime_ref]);
return;
}
if lifetime_ref.is_static() {
Expand Down Expand Up @@ -1691,7 +1691,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
_ => None,
}).collect();
if elide_lifetimes {
self.resolve_elided_lifetimes(lifetimes, true);
self.resolve_elided_lifetimes(lifetimes);
} else {
lifetimes.iter().for_each(|lt| self.visit_lifetime(lt));
}
Expand Down Expand Up @@ -2069,26 +2069,14 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
}

fn resolve_elided_lifetimes(&mut self,
lifetime_refs: Vec<&'tcx hir::Lifetime>,
deprecated: bool) {
lifetime_refs: Vec<&'tcx hir::Lifetime>) {
if lifetime_refs.is_empty() {
return;
}

let span = lifetime_refs[0].span;
let id = lifetime_refs[0].id;
let mut late_depth = 0;
let mut scope = self.scope;
if deprecated {
self.tcx
.struct_span_lint_node(
lint::builtin::ELIDED_LIFETIMES_IN_PATHS,
id,
span,
&format!("hidden lifetime parameters are deprecated, try `Foo<'_>`"),
)
.emit();
}
let error = loop {
match *scope {
// Do not assign any resolution, it will be inferred.
Expand Down
86 changes: 86 additions & 0 deletions src/test/ui/in-band-lifetimes/elided-lifetimes.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// run-rustfix
// compile-flags: --edition 2018

#![allow(unused)]
#![deny(elided_lifetimes_in_paths)]
//~^ NOTE lint level defined here

use std::cell::{RefCell, Ref};


struct Foo<'a> { x: &'a u32 }

fn foo(x: &Foo) {
//~^ ERROR hidden lifetime parameters in types are deprecated
//~| HELP indicate the anonymous lifetime
}

fn bar(x: &Foo<'_>) {}


struct Wrapped<'a>(&'a str);

struct WrappedWithBow<'a> {
gift: &'a str
}

fn wrap_gift(gift: &str) -> Wrapped {
//~^ ERROR hidden lifetime parameters in types are deprecated
//~| HELP indicate the anonymous lifetime
Wrapped(gift)
}

fn wrap_gift_with_bow(gift: &str) -> WrappedWithBow {
//~^ ERROR hidden lifetime parameters in types are deprecated
//~| HELP indicate the anonymous lifetime
WrappedWithBow { gift }
}

macro_rules! autowrapper {
($type_name:ident, $fn_name:ident, $lt:lifetime) => {
struct $type_name<$lt> {
gift: &$lt str
}

fn $fn_name(gift: &str) -> $type_name {
//~^ ERROR hidden lifetime parameters in types are deprecated
//~| HELP indicate the anonymous lifetime
$type_name { gift }
}
}
}

autowrapper!(Autowrapped, autowrap_gift, 'a);
//~^ NOTE in this expansion of autowrapper!
//~| NOTE in this expansion of autowrapper!

macro_rules! anytuple_ref_ty {
($($types:ty),*) => {
Ref<($($types),*)>
//~^ ERROR hidden lifetime parameters in types are deprecated
//~| HELP indicate the anonymous lifetime
}
}

fn main() {
let honesty = RefCell::new((4, 'e'));
let loyalty: Ref<(u32, char)> = honesty.borrow();
//~^ ERROR hidden lifetime parameters in types are deprecated
//~| HELP indicate the anonymous lifetime
let generosity = Ref::map(loyalty, |t| &t.0);

let laughter = RefCell::new((true, "magic"));
let yellow: anytuple_ref_ty!(bool, &str) = laughter.borrow();
//~^ NOTE in this expansion of anytuple_ref_ty!
//~| NOTE in this expansion of anytuple_ref_ty!
}
19 changes: 0 additions & 19 deletions src/test/ui/in-band-lifetimes/ellided-lifetimes.rs

This file was deleted.

14 changes: 0 additions & 14 deletions src/test/ui/in-band-lifetimes/ellided-lifetimes.stderr

This file was deleted.

0 comments on commit 4f51df6

Please sign in to comment.