Diagnose shadowing on AST.
This commit is contained in:
parent
20976bae5c
commit
6e1b0105c6
3 changed files with 209 additions and 325 deletions
|
@ -12,6 +12,10 @@ use crate::{path_names_to_string, BindingError, Finalize, LexicalScopeBinding};
|
||||||
use crate::{Module, ModuleOrUniformRoot, NameBinding, ParentScope, PathResult};
|
use crate::{Module, ModuleOrUniformRoot, NameBinding, ParentScope, PathResult};
|
||||||
use crate::{ResolutionError, Resolver, Segment, UseError};
|
use crate::{ResolutionError, Resolver, Segment, UseError};
|
||||||
|
|
||||||
|
use diagnostics::{
|
||||||
|
original_label, original_lifetime, original_lifetime_param, shadower_label, shadower_lifetime,
|
||||||
|
};
|
||||||
|
|
||||||
use rustc_ast::ptr::P;
|
use rustc_ast::ptr::P;
|
||||||
use rustc_ast::visit::{self, AssocCtxt, BoundKind, FnCtxt, FnKind, Visitor};
|
use rustc_ast::visit::{self, AssocCtxt, BoundKind, FnCtxt, FnKind, Visitor};
|
||||||
use rustc_ast::*;
|
use rustc_ast::*;
|
||||||
|
@ -172,6 +176,23 @@ impl RibKind<'_> {
|
||||||
AssocItemRibKind | ItemRibKind(_) | ForwardGenericParamBanRibKind => true,
|
AssocItemRibKind | ItemRibKind(_) | ForwardGenericParamBanRibKind => true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// This rib forbids referring to labels defined in upwards ribs.
|
||||||
|
fn is_label_barrier(self) -> bool {
|
||||||
|
match self {
|
||||||
|
NormalRibKind | MacroDefinition(..) => false,
|
||||||
|
|
||||||
|
AssocItemRibKind
|
||||||
|
| ClosureOrAsyncRibKind
|
||||||
|
| FnItemRibKind
|
||||||
|
| ItemRibKind(..)
|
||||||
|
| ConstantItemRibKind(..)
|
||||||
|
| ModuleRibKind(..)
|
||||||
|
| ForwardGenericParamBanRibKind
|
||||||
|
| ConstParamTyRibKind
|
||||||
|
| InlineAsmSymRibKind => true,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A single local scope.
|
/// A single local scope.
|
||||||
|
@ -732,7 +753,7 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> {
|
||||||
// Create a value rib for the function.
|
// Create a value rib for the function.
|
||||||
self.with_rib(ValueNS, rib_kind, |this| {
|
self.with_rib(ValueNS, rib_kind, |this| {
|
||||||
// Create a label rib for the function.
|
// Create a label rib for the function.
|
||||||
this.with_label_rib(rib_kind, |this| {
|
this.with_label_rib(FnItemRibKind, |this| {
|
||||||
let async_node_id = fn_kind.header().and_then(|h| h.asyncness.opt_return_id());
|
let async_node_id = fn_kind.header().and_then(|h| h.asyncness.opt_return_id());
|
||||||
|
|
||||||
if let FnKind::Fn(_, _, _, _, generics, _) = fn_kind {
|
if let FnKind::Fn(_, _, _, _, generics, _) = fn_kind {
|
||||||
|
@ -1585,24 +1606,10 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
|
||||||
let ribs = &self.label_ribs[rib_index + 1..];
|
let ribs = &self.label_ribs[rib_index + 1..];
|
||||||
|
|
||||||
for rib in ribs {
|
for rib in ribs {
|
||||||
match rib.kind {
|
if rib.kind.is_label_barrier() {
|
||||||
NormalRibKind | MacroDefinition(..) => {
|
|
||||||
// Nothing to do. Continue.
|
|
||||||
}
|
|
||||||
|
|
||||||
AssocItemRibKind
|
|
||||||
| ClosureOrAsyncRibKind
|
|
||||||
| FnItemRibKind
|
|
||||||
| ItemRibKind(..)
|
|
||||||
| ConstantItemRibKind(..)
|
|
||||||
| ModuleRibKind(..)
|
|
||||||
| ForwardGenericParamBanRibKind
|
|
||||||
| ConstParamTyRibKind
|
|
||||||
| InlineAsmSymRibKind => {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
@ -1895,6 +1902,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
|
||||||
let mut function_value_rib = Rib::new(kind);
|
let mut function_value_rib = Rib::new(kind);
|
||||||
let mut function_lifetime_rib = LifetimeRib::new(lifetime_kind);
|
let mut function_lifetime_rib = LifetimeRib::new(lifetime_kind);
|
||||||
let mut seen_bindings = FxHashMap::default();
|
let mut seen_bindings = FxHashMap::default();
|
||||||
|
let mut seen_lifetimes = FxHashMap::default();
|
||||||
|
|
||||||
// We also can't shadow bindings from the parent item
|
// We also can't shadow bindings from the parent item
|
||||||
if let AssocItemRibKind = kind {
|
if let AssocItemRibKind = kind {
|
||||||
|
@ -1910,22 +1918,54 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
|
||||||
add_bindings_for_ns(TypeNS);
|
add_bindings_for_ns(TypeNS);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Forbid shadowing lifetime bindings
|
||||||
|
for rib in self.lifetime_ribs.iter().rev() {
|
||||||
|
seen_lifetimes.extend(
|
||||||
|
rib.bindings.iter().map(|(ident, _)| (*ident, original_lifetime(ident.span))),
|
||||||
|
);
|
||||||
|
if let LifetimeRibKind::Item = rib.kind {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for rib in self.label_ribs.iter().rev() {
|
||||||
|
if rib.kind.is_label_barrier() {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
seen_lifetimes
|
||||||
|
.extend(rib.bindings.iter().map(|(ident, _)| (*ident, original_label(ident.span))));
|
||||||
|
}
|
||||||
|
|
||||||
for param in params {
|
for param in params {
|
||||||
let ident = param.ident.normalize_to_macros_2_0();
|
let ident = param.ident.normalize_to_macros_2_0();
|
||||||
debug!("with_generic_param_rib: {}", param.id);
|
debug!("with_generic_param_rib: {}", param.id);
|
||||||
|
|
||||||
|
if let GenericParamKind::Lifetime = param.kind {
|
||||||
|
match seen_lifetimes.entry(ident) {
|
||||||
|
Entry::Occupied(entry) => {
|
||||||
|
let original = *entry.get();
|
||||||
|
diagnostics::signal_shadowing_problem(
|
||||||
|
self.r.session,
|
||||||
|
ident.name,
|
||||||
|
original,
|
||||||
|
shadower_lifetime(param.ident.span),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Entry::Vacant(entry) => {
|
||||||
|
entry.insert(original_lifetime_param(param.ident.span));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
match seen_bindings.entry(ident) {
|
match seen_bindings.entry(ident) {
|
||||||
Entry::Occupied(entry) => {
|
Entry::Occupied(entry) => {
|
||||||
let span = *entry.get();
|
let span = *entry.get();
|
||||||
let err = ResolutionError::NameAlreadyUsedInParameterList(ident.name, span);
|
let err = ResolutionError::NameAlreadyUsedInParameterList(ident.name, span);
|
||||||
if !matches!(param.kind, GenericParamKind::Lifetime) {
|
|
||||||
self.report_error(param.ident.span, err);
|
self.report_error(param.ident.span, err);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
Entry::Vacant(entry) => {
|
Entry::Vacant(entry) => {
|
||||||
entry.insert(param.ident.span);
|
entry.insert(param.ident.span);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if param.ident.name == kw::UnderscoreLifetime {
|
if param.ident.name == kw::UnderscoreLifetime {
|
||||||
rustc_errors::struct_span_err!(
|
rustc_errors::struct_span_err!(
|
||||||
|
@ -3114,8 +3154,35 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
|
||||||
if label.ident.as_str().as_bytes()[1] != b'_' {
|
if label.ident.as_str().as_bytes()[1] != b'_' {
|
||||||
self.diagnostic_metadata.unused_labels.insert(id, label.ident.span);
|
self.diagnostic_metadata.unused_labels.insert(id, label.ident.span);
|
||||||
}
|
}
|
||||||
self.with_label_rib(NormalRibKind, |this| {
|
|
||||||
|
// Forbid shadowing lifetime bindings
|
||||||
let ident = label.ident.normalize_to_macro_rules();
|
let ident = label.ident.normalize_to_macro_rules();
|
||||||
|
for rib in self.lifetime_ribs.iter().rev() {
|
||||||
|
if let Some((orig_ident, _)) = rib.bindings.get_key_value(&ident) {
|
||||||
|
diagnostics::signal_shadowing_problem(
|
||||||
|
self.r.session,
|
||||||
|
label.ident.name,
|
||||||
|
original_lifetime(orig_ident.span),
|
||||||
|
shadower_label(label.ident.span),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for rib in self.label_ribs.iter_mut().rev() {
|
||||||
|
if let Some((orig_ident, _)) = rib.bindings.get_key_value(&ident) {
|
||||||
|
diagnostics::signal_shadowing_problem(
|
||||||
|
self.r.session,
|
||||||
|
label.ident.name,
|
||||||
|
original_label(orig_ident.span),
|
||||||
|
shadower_label(label.ident.span),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
if rib.kind.is_label_barrier() {
|
||||||
|
rib.bindings.insert(ident, id);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.with_label_rib(NormalRibKind, |this| {
|
||||||
this.label_ribs.last_mut().unwrap().bindings.insert(ident, id);
|
this.label_ribs.last_mut().unwrap().bindings.insert(ident, id);
|
||||||
f(this);
|
f(this);
|
||||||
});
|
});
|
||||||
|
|
|
@ -25,6 +25,7 @@ use rustc_hir::def_id::{DefId, CRATE_DEF_ID, LOCAL_CRATE};
|
||||||
use rustc_hir::PrimTy;
|
use rustc_hir::PrimTy;
|
||||||
use rustc_session::lint;
|
use rustc_session::lint;
|
||||||
use rustc_session::parse::feature_err;
|
use rustc_session::parse::feature_err;
|
||||||
|
use rustc_session::Session;
|
||||||
use rustc_span::edition::Edition;
|
use rustc_span::edition::Edition;
|
||||||
use rustc_span::hygiene::MacroKind;
|
use rustc_span::hygiene::MacroKind;
|
||||||
use rustc_span::lev_distance::find_best_match_for_name;
|
use rustc_span::lev_distance::find_best_match_for_name;
|
||||||
|
@ -2036,6 +2037,87 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, PartialEq)]
|
||||||
|
enum ShadowKind {
|
||||||
|
Label,
|
||||||
|
Lifetime,
|
||||||
|
}
|
||||||
|
#[derive(Copy, Clone)]
|
||||||
|
pub struct Original {
|
||||||
|
kind: ShadowKind,
|
||||||
|
span: Span,
|
||||||
|
param: bool,
|
||||||
|
}
|
||||||
|
#[derive(Copy, Clone)]
|
||||||
|
pub struct Shadower {
|
||||||
|
kind: ShadowKind,
|
||||||
|
span: Span,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn original_label(span: Span) -> Original {
|
||||||
|
Original { kind: ShadowKind::Label, span, param: false }
|
||||||
|
}
|
||||||
|
pub fn shadower_label(span: Span) -> Shadower {
|
||||||
|
Shadower { kind: ShadowKind::Label, span }
|
||||||
|
}
|
||||||
|
pub fn original_lifetime(span: Span) -> Original {
|
||||||
|
Original { kind: ShadowKind::Lifetime, span, param: false }
|
||||||
|
}
|
||||||
|
pub fn original_lifetime_param(span: Span) -> Original {
|
||||||
|
Original { kind: ShadowKind::Lifetime, span, param: true }
|
||||||
|
}
|
||||||
|
pub fn shadower_lifetime(span: Span) -> Shadower {
|
||||||
|
Shadower { kind: ShadowKind::Lifetime, span }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ShadowKind {
|
||||||
|
fn desc(&self) -> &'static str {
|
||||||
|
match *self {
|
||||||
|
ShadowKind::Label => "label",
|
||||||
|
ShadowKind::Lifetime => "lifetime",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn signal_shadowing_problem(sess: &Session, name: Symbol, orig: Original, shadower: Shadower) {
|
||||||
|
let mut err = if let (ShadowKind::Lifetime, ShadowKind::Lifetime) = (orig.kind, shadower.kind) {
|
||||||
|
// lifetime/lifetime shadowing is an error
|
||||||
|
if orig.param {
|
||||||
|
struct_span_err!(
|
||||||
|
sess,
|
||||||
|
shadower.span,
|
||||||
|
E0263,
|
||||||
|
"lifetime name `{}` declared twice in the same scope",
|
||||||
|
name,
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
struct_span_err!(
|
||||||
|
sess,
|
||||||
|
shadower.span,
|
||||||
|
E0496,
|
||||||
|
"lifetime name `{}` shadows a lifetime name that is already in scope",
|
||||||
|
name,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
.forget_guarantee()
|
||||||
|
} else {
|
||||||
|
// shadowing involving a label is only a warning, due to issues with
|
||||||
|
// labels and lifetimes not being macro-hygienic.
|
||||||
|
sess.struct_span_warn(
|
||||||
|
shadower.span,
|
||||||
|
&format!(
|
||||||
|
"{} name `{}` shadows a {} name that is already in scope",
|
||||||
|
shadower.kind.desc(),
|
||||||
|
name,
|
||||||
|
orig.kind.desc()
|
||||||
|
),
|
||||||
|
)
|
||||||
|
};
|
||||||
|
err.span_label(orig.span, "first declared here");
|
||||||
|
err.span_label(shadower.span, format!("{} `{}` already in scope", orig.kind.desc(), name));
|
||||||
|
err.emit();
|
||||||
|
}
|
||||||
|
|
||||||
impl<'tcx> LifetimeContext<'_, 'tcx> {
|
impl<'tcx> LifetimeContext<'_, 'tcx> {
|
||||||
pub(crate) fn report_missing_lifetime_specifiers(
|
pub(crate) fn report_missing_lifetime_specifiers(
|
||||||
&self,
|
&self,
|
||||||
|
|
|
@ -23,7 +23,7 @@ use rustc_middle::middle::resolve_lifetime::*;
|
||||||
use rustc_middle::ty::{self, DefIdTree, GenericParamDefKind, TyCtxt};
|
use rustc_middle::ty::{self, DefIdTree, GenericParamDefKind, TyCtxt};
|
||||||
use rustc_middle::{bug, span_bug};
|
use rustc_middle::{bug, span_bug};
|
||||||
use rustc_span::def_id::DefId;
|
use rustc_span::def_id::DefId;
|
||||||
use rustc_span::symbol::{kw, sym, Ident, Symbol};
|
use rustc_span::symbol::{kw, sym, Ident};
|
||||||
use rustc_span::Span;
|
use rustc_span::Span;
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
use std::cell::Cell;
|
use std::cell::Cell;
|
||||||
|
@ -161,9 +161,6 @@ pub(crate) struct LifetimeContext<'a, 'tcx> {
|
||||||
/// we eventually need lifetimes resolve for trait items.
|
/// we eventually need lifetimes resolve for trait items.
|
||||||
trait_definition_only: bool,
|
trait_definition_only: bool,
|
||||||
|
|
||||||
/// List of labels in the function/method currently under analysis.
|
|
||||||
labels_in_fn: Vec<Ident>,
|
|
||||||
|
|
||||||
/// Cache for cross-crate per-definition object lifetime defaults.
|
/// Cache for cross-crate per-definition object lifetime defaults.
|
||||||
xcrate_object_lifetime_defaults: DefIdMap<Vec<ObjectLifetimeDefault>>,
|
xcrate_object_lifetime_defaults: DefIdMap<Vec<ObjectLifetimeDefault>>,
|
||||||
|
|
||||||
|
@ -434,7 +431,6 @@ fn do_resolve(
|
||||||
map: &mut named_region_map,
|
map: &mut named_region_map,
|
||||||
scope: ROOT_SCOPE,
|
scope: ROOT_SCOPE,
|
||||||
trait_definition_only,
|
trait_definition_only,
|
||||||
labels_in_fn: vec![],
|
|
||||||
xcrate_object_lifetime_defaults: Default::default(),
|
xcrate_object_lifetime_defaults: Default::default(),
|
||||||
missing_named_lifetime_spots: vec![],
|
missing_named_lifetime_spots: vec![],
|
||||||
};
|
};
|
||||||
|
@ -641,14 +637,10 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_nested_body(&mut self, body: hir::BodyId) {
|
fn visit_nested_body(&mut self, body: hir::BodyId) {
|
||||||
// Each body has their own set of labels, save labels.
|
|
||||||
let saved = take(&mut self.labels_in_fn);
|
|
||||||
let body = self.tcx.hir().body(body);
|
let body = self.tcx.hir().body(body);
|
||||||
extract_labels(self, body);
|
self.with(Scope::Body { id: body.id(), s: self.scope }, |this| {
|
||||||
self.with(Scope::Body { id: body.id(), s: self.scope }, |_, this| {
|
|
||||||
this.visit_body(body);
|
this.visit_body(body);
|
||||||
});
|
});
|
||||||
self.labels_in_fn = saved;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_fn(
|
fn visit_fn(
|
||||||
|
@ -683,9 +675,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
|
||||||
scope_type: BinderScopeType::Normal,
|
scope_type: BinderScopeType::Normal,
|
||||||
allow_late_bound: true,
|
allow_late_bound: true,
|
||||||
};
|
};
|
||||||
self.with(scope, move |_old_scope, this| {
|
self.with(scope, move |this| intravisit::walk_fn(this, fk, fd, b, s, hir_id));
|
||||||
intravisit::walk_fn(this, fk, fd, b, s, hir_id)
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -720,7 +710,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
|
||||||
hir::ItemKind::Static(..) | hir::ItemKind::Const(..) => {
|
hir::ItemKind::Static(..) | hir::ItemKind::Const(..) => {
|
||||||
// No lifetime parameters, but implied 'static.
|
// No lifetime parameters, but implied 'static.
|
||||||
let scope = Scope::Elision { elide: Elide::Exact(Region::Static), s: ROOT_SCOPE };
|
let scope = Scope::Elision { elide: Elide::Exact(Region::Static), s: ROOT_SCOPE };
|
||||||
self.with(scope, |_, this| intravisit::walk_item(this, item));
|
self.with(scope, |this| intravisit::walk_item(this, item));
|
||||||
}
|
}
|
||||||
hir::ItemKind::OpaqueTy(hir::OpaqueTy { .. }) => {
|
hir::ItemKind::OpaqueTy(hir::OpaqueTy { .. }) => {
|
||||||
// Opaque types are visited when we visit the
|
// Opaque types are visited when we visit the
|
||||||
|
@ -807,10 +797,9 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
|
||||||
s: ROOT_SCOPE,
|
s: ROOT_SCOPE,
|
||||||
allow_late_bound: false,
|
allow_late_bound: false,
|
||||||
};
|
};
|
||||||
self.with(scope, |old_scope, this| {
|
self.with(scope, |this| {
|
||||||
this.check_lifetime_params(old_scope, &generics.params);
|
|
||||||
let scope = Scope::TraitRefBoundary { s: this.scope };
|
let scope = Scope::TraitRefBoundary { s: this.scope };
|
||||||
this.with(scope, |_, this| {
|
this.with(scope, |this| {
|
||||||
intravisit::walk_item(this, item);
|
intravisit::walk_item(this, item);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -873,10 +862,9 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
|
||||||
scope_type: BinderScopeType::Normal,
|
scope_type: BinderScopeType::Normal,
|
||||||
allow_late_bound: true,
|
allow_late_bound: true,
|
||||||
};
|
};
|
||||||
self.with(scope, |old_scope, this| {
|
self.with(scope, |this| {
|
||||||
// a bare fn has no bounds, so everything
|
// a bare fn has no bounds, so everything
|
||||||
// contained within is scoped within its binder.
|
// contained within is scoped within its binder.
|
||||||
this.check_lifetime_params(old_scope, &c.generic_params);
|
|
||||||
intravisit::walk_ty(this, ty);
|
intravisit::walk_ty(this, ty);
|
||||||
});
|
});
|
||||||
self.missing_named_lifetime_spots.pop();
|
self.missing_named_lifetime_spots.pop();
|
||||||
|
@ -884,7 +872,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
|
||||||
hir::TyKind::TraitObject(bounds, ref lifetime, _) => {
|
hir::TyKind::TraitObject(bounds, ref lifetime, _) => {
|
||||||
debug!(?bounds, ?lifetime, "TraitObject");
|
debug!(?bounds, ?lifetime, "TraitObject");
|
||||||
let scope = Scope::TraitRefBoundary { s: self.scope };
|
let scope = Scope::TraitRefBoundary { s: self.scope };
|
||||||
self.with(scope, |_, this| {
|
self.with(scope, |this| {
|
||||||
for bound in bounds {
|
for bound in bounds {
|
||||||
this.visit_poly_trait_ref(bound, hir::TraitBoundModifier::None);
|
this.visit_poly_trait_ref(bound, hir::TraitBoundModifier::None);
|
||||||
}
|
}
|
||||||
|
@ -923,7 +911,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
|
||||||
lifetime: self.map.defs.get(&lifetime_ref.hir_id).cloned(),
|
lifetime: self.map.defs.get(&lifetime_ref.hir_id).cloned(),
|
||||||
s: self.scope,
|
s: self.scope,
|
||||||
};
|
};
|
||||||
self.with(scope, |_, this| this.visit_ty(&mt.ty));
|
self.with(scope, |this| this.visit_ty(&mt.ty));
|
||||||
}
|
}
|
||||||
hir::TyKind::OpaqueDef(item_id, lifetimes) => {
|
hir::TyKind::OpaqueDef(item_id, lifetimes) => {
|
||||||
// Resolve the lifetimes in the bounds to the lifetime defs in the generics.
|
// Resolve the lifetimes in the bounds to the lifetime defs in the generics.
|
||||||
|
@ -944,9 +932,9 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
|
||||||
// Elided lifetimes are not allowed in non-return
|
// Elided lifetimes are not allowed in non-return
|
||||||
// position impl Trait
|
// position impl Trait
|
||||||
let scope = Scope::TraitRefBoundary { s: self.scope };
|
let scope = Scope::TraitRefBoundary { s: self.scope };
|
||||||
self.with(scope, |_, this| {
|
self.with(scope, |this| {
|
||||||
let scope = Scope::Elision { elide: Elide::Forbid, s: this.scope };
|
let scope = Scope::Elision { elide: Elide::Forbid, s: this.scope };
|
||||||
this.with(scope, |_, this| {
|
this.with(scope, |this| {
|
||||||
intravisit::walk_item(this, opaque_ty);
|
intravisit::walk_item(this, opaque_ty);
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
@ -1052,7 +1040,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
|
||||||
if let Some(elision_region) = elision {
|
if let Some(elision_region) = elision {
|
||||||
let scope =
|
let scope =
|
||||||
Scope::Elision { elide: Elide::Exact(elision_region), s: self.scope };
|
Scope::Elision { elide: Elide::Exact(elision_region), s: self.scope };
|
||||||
self.with(scope, |_old_scope, this| {
|
self.with(scope, |this| {
|
||||||
let scope = Scope::Binder {
|
let scope = Scope::Binder {
|
||||||
hir_id: ty.hir_id,
|
hir_id: ty.hir_id,
|
||||||
lifetimes,
|
lifetimes,
|
||||||
|
@ -1062,10 +1050,10 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
|
||||||
scope_type: BinderScopeType::Normal,
|
scope_type: BinderScopeType::Normal,
|
||||||
allow_late_bound: false,
|
allow_late_bound: false,
|
||||||
};
|
};
|
||||||
this.with(scope, |_old_scope, this| {
|
this.with(scope, |this| {
|
||||||
this.visit_generics(generics);
|
this.visit_generics(generics);
|
||||||
let scope = Scope::TraitRefBoundary { s: this.scope };
|
let scope = Scope::TraitRefBoundary { s: this.scope };
|
||||||
this.with(scope, |_, this| {
|
this.with(scope, |this| {
|
||||||
for bound in bounds {
|
for bound in bounds {
|
||||||
this.visit_param_bound(bound);
|
this.visit_param_bound(bound);
|
||||||
}
|
}
|
||||||
|
@ -1082,9 +1070,9 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
|
||||||
scope_type: BinderScopeType::Normal,
|
scope_type: BinderScopeType::Normal,
|
||||||
allow_late_bound: false,
|
allow_late_bound: false,
|
||||||
};
|
};
|
||||||
self.with(scope, |_old_scope, this| {
|
self.with(scope, |this| {
|
||||||
let scope = Scope::TraitRefBoundary { s: this.scope };
|
let scope = Scope::TraitRefBoundary { s: this.scope };
|
||||||
this.with(scope, |_, this| {
|
this.with(scope, |this| {
|
||||||
this.visit_generics(generics);
|
this.visit_generics(generics);
|
||||||
for bound in bounds {
|
for bound in bounds {
|
||||||
this.visit_param_bound(bound);
|
this.visit_param_bound(bound);
|
||||||
|
@ -1141,10 +1129,9 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
|
||||||
scope_type: BinderScopeType::Normal,
|
scope_type: BinderScopeType::Normal,
|
||||||
allow_late_bound: false,
|
allow_late_bound: false,
|
||||||
};
|
};
|
||||||
self.with(scope, |old_scope, this| {
|
self.with(scope, |this| {
|
||||||
this.check_lifetime_params(old_scope, &generics.params);
|
|
||||||
let scope = Scope::TraitRefBoundary { s: this.scope };
|
let scope = Scope::TraitRefBoundary { s: this.scope };
|
||||||
this.with(scope, |_, this| {
|
this.with(scope, |this| {
|
||||||
this.visit_generics(generics);
|
this.visit_generics(generics);
|
||||||
for bound in bounds {
|
for bound in bounds {
|
||||||
this.visit_param_bound(bound);
|
this.visit_param_bound(bound);
|
||||||
|
@ -1210,10 +1197,9 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
|
||||||
scope_type: BinderScopeType::Normal,
|
scope_type: BinderScopeType::Normal,
|
||||||
allow_late_bound: true,
|
allow_late_bound: true,
|
||||||
};
|
};
|
||||||
self.with(scope, |old_scope, this| {
|
self.with(scope, |this| {
|
||||||
this.check_lifetime_params(old_scope, &generics.params);
|
|
||||||
let scope = Scope::TraitRefBoundary { s: this.scope };
|
let scope = Scope::TraitRefBoundary { s: this.scope };
|
||||||
this.with(scope, |_, this| {
|
this.with(scope, |this| {
|
||||||
this.visit_generics(generics);
|
this.visit_generics(generics);
|
||||||
this.visit_ty(ty);
|
this.visit_ty(ty);
|
||||||
})
|
})
|
||||||
|
@ -1300,7 +1286,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
|
||||||
|
|
||||||
fn visit_generics(&mut self, generics: &'tcx hir::Generics<'tcx>) {
|
fn visit_generics(&mut self, generics: &'tcx hir::Generics<'tcx>) {
|
||||||
let scope = Scope::TraitRefBoundary { s: self.scope };
|
let scope = Scope::TraitRefBoundary { s: self.scope };
|
||||||
self.with(scope, |_, this| {
|
self.with(scope, |this| {
|
||||||
for param in generics.params {
|
for param in generics.params {
|
||||||
match param.kind {
|
match param.kind {
|
||||||
GenericParamKind::Lifetime { .. } => {}
|
GenericParamKind::Lifetime { .. } => {}
|
||||||
|
@ -1354,8 +1340,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
|
||||||
scope_type: BinderScopeType::Normal,
|
scope_type: BinderScopeType::Normal,
|
||||||
allow_late_bound: true,
|
allow_late_bound: true,
|
||||||
};
|
};
|
||||||
this.with(scope, |old_scope, this| {
|
this.with(scope, |this| {
|
||||||
this.check_lifetime_params(old_scope, &bound_generic_params);
|
|
||||||
this.visit_ty(&bounded_ty);
|
this.visit_ty(&bounded_ty);
|
||||||
walk_list!(this, visit_param_bound, bounds);
|
walk_list!(this, visit_param_bound, bounds);
|
||||||
})
|
})
|
||||||
|
@ -1427,7 +1412,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
|
||||||
scope_type,
|
scope_type,
|
||||||
allow_late_bound: true,
|
allow_late_bound: true,
|
||||||
};
|
};
|
||||||
self.with(scope, |_, this| {
|
self.with(scope, |this| {
|
||||||
intravisit::walk_param_bound(this, bound);
|
intravisit::walk_param_bound(this, bound);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -1479,8 +1464,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
|
||||||
scope_type,
|
scope_type,
|
||||||
allow_late_bound: true,
|
allow_late_bound: true,
|
||||||
};
|
};
|
||||||
self.with(scope, |old_scope, this| {
|
self.with(scope, |this| {
|
||||||
this.check_lifetime_params(old_scope, &trait_ref.bound_generic_params);
|
|
||||||
walk_list!(this, visit_generic_param, trait_ref.bound_generic_params);
|
walk_list!(this, visit_generic_param, trait_ref.bound_generic_params);
|
||||||
this.visit_trait_ref(&trait_ref.trait_ref);
|
this.visit_trait_ref(&trait_ref.trait_ref);
|
||||||
});
|
});
|
||||||
|
@ -1491,154 +1475,6 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, PartialEq)]
|
|
||||||
enum ShadowKind {
|
|
||||||
Label,
|
|
||||||
Lifetime,
|
|
||||||
}
|
|
||||||
struct Original {
|
|
||||||
kind: ShadowKind,
|
|
||||||
span: Span,
|
|
||||||
}
|
|
||||||
struct Shadower {
|
|
||||||
kind: ShadowKind,
|
|
||||||
span: Span,
|
|
||||||
}
|
|
||||||
|
|
||||||
fn original_label(span: Span) -> Original {
|
|
||||||
Original { kind: ShadowKind::Label, span }
|
|
||||||
}
|
|
||||||
fn shadower_label(span: Span) -> Shadower {
|
|
||||||
Shadower { kind: ShadowKind::Label, span }
|
|
||||||
}
|
|
||||||
fn original_lifetime(span: Span) -> Original {
|
|
||||||
Original { kind: ShadowKind::Lifetime, span }
|
|
||||||
}
|
|
||||||
fn shadower_lifetime(param: &hir::GenericParam<'_>) -> Shadower {
|
|
||||||
Shadower { kind: ShadowKind::Lifetime, span: param.span }
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ShadowKind {
|
|
||||||
fn desc(&self) -> &'static str {
|
|
||||||
match *self {
|
|
||||||
ShadowKind::Label => "label",
|
|
||||||
ShadowKind::Lifetime => "lifetime",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn signal_shadowing_problem(tcx: TyCtxt<'_>, name: Symbol, orig: Original, shadower: Shadower) {
|
|
||||||
let mut err = if let (ShadowKind::Lifetime, ShadowKind::Lifetime) = (orig.kind, shadower.kind) {
|
|
||||||
// lifetime/lifetime shadowing is an error
|
|
||||||
struct_span_err!(
|
|
||||||
tcx.sess,
|
|
||||||
shadower.span,
|
|
||||||
E0496,
|
|
||||||
"{} name `{}` shadows a \
|
|
||||||
{} name that is already in scope",
|
|
||||||
shadower.kind.desc(),
|
|
||||||
name,
|
|
||||||
orig.kind.desc()
|
|
||||||
)
|
|
||||||
.forget_guarantee()
|
|
||||||
} else {
|
|
||||||
// shadowing involving a label is only a warning, due to issues with
|
|
||||||
// labels and lifetimes not being macro-hygienic.
|
|
||||||
tcx.sess.struct_span_warn(
|
|
||||||
shadower.span,
|
|
||||||
&format!(
|
|
||||||
"{} name `{}` shadows a \
|
|
||||||
{} name that is already in scope",
|
|
||||||
shadower.kind.desc(),
|
|
||||||
name,
|
|
||||||
orig.kind.desc()
|
|
||||||
),
|
|
||||||
)
|
|
||||||
};
|
|
||||||
err.span_label(orig.span, "first declared here");
|
|
||||||
err.span_label(shadower.span, format!("{} `{}` already in scope", orig.kind.desc(), name));
|
|
||||||
err.emit();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Adds all labels in `b` to `ctxt.labels_in_fn`, signalling a warning
|
|
||||||
// if one of the label shadows a lifetime or another label.
|
|
||||||
fn extract_labels(ctxt: &mut LifetimeContext<'_, '_>, body: &hir::Body<'_>) {
|
|
||||||
struct GatherLabels<'a, 'tcx> {
|
|
||||||
tcx: TyCtxt<'tcx>,
|
|
||||||
scope: ScopeRef<'a>,
|
|
||||||
labels_in_fn: &'a mut Vec<Ident>,
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut gather =
|
|
||||||
GatherLabels { tcx: ctxt.tcx, scope: ctxt.scope, labels_in_fn: &mut ctxt.labels_in_fn };
|
|
||||||
gather.visit_body(body);
|
|
||||||
|
|
||||||
impl<'v, 'a, 'tcx> Visitor<'v> for GatherLabels<'a, 'tcx> {
|
|
||||||
fn visit_expr(&mut self, ex: &hir::Expr<'_>) {
|
|
||||||
if let Some(label) = expression_label(ex) {
|
|
||||||
for prior_label in &self.labels_in_fn[..] {
|
|
||||||
// FIXME (#24278): non-hygienic comparison
|
|
||||||
if label.name == prior_label.name {
|
|
||||||
signal_shadowing_problem(
|
|
||||||
self.tcx,
|
|
||||||
label.name,
|
|
||||||
original_label(prior_label.span),
|
|
||||||
shadower_label(label.span),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
check_if_label_shadows_lifetime(self.tcx, self.scope, label);
|
|
||||||
|
|
||||||
self.labels_in_fn.push(label);
|
|
||||||
}
|
|
||||||
intravisit::walk_expr(self, ex)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn expression_label(ex: &hir::Expr<'_>) -> Option<Ident> {
|
|
||||||
match ex.kind {
|
|
||||||
hir::ExprKind::Loop(_, Some(label), ..) => Some(label.ident),
|
|
||||||
hir::ExprKind::Block(_, Some(label)) => Some(label.ident),
|
|
||||||
_ => None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn check_if_label_shadows_lifetime(tcx: TyCtxt<'_>, mut scope: ScopeRef<'_>, label: Ident) {
|
|
||||||
loop {
|
|
||||||
match *scope {
|
|
||||||
Scope::Body { s, .. }
|
|
||||||
| Scope::Elision { s, .. }
|
|
||||||
| Scope::ObjectLifetimeDefault { s, .. }
|
|
||||||
| Scope::Supertrait { s, .. }
|
|
||||||
| Scope::TraitRefBoundary { s, .. } => {
|
|
||||||
scope = s;
|
|
||||||
}
|
|
||||||
|
|
||||||
Scope::Root => {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Scope::Binder { ref lifetimes, s, .. } => {
|
|
||||||
// FIXME (#24278): non-hygienic comparison
|
|
||||||
if let Some(def) =
|
|
||||||
lifetimes.get(&hir::ParamName::Plain(label.normalize_to_macros_2_0()))
|
|
||||||
{
|
|
||||||
signal_shadowing_problem(
|
|
||||||
tcx,
|
|
||||||
label.name,
|
|
||||||
original_lifetime(tcx.def_span(def.id().unwrap().expect_local())),
|
|
||||||
shadower_label(label.span),
|
|
||||||
);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
scope = s;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn compute_object_lifetime_defaults<'tcx>(
|
fn compute_object_lifetime_defaults<'tcx>(
|
||||||
tcx: TyCtxt<'tcx>,
|
tcx: TyCtxt<'tcx>,
|
||||||
item: &hir::Item<'_>,
|
item: &hir::Item<'_>,
|
||||||
|
@ -1774,10 +1610,9 @@ fn object_lifetime_defaults_for_item<'tcx>(
|
||||||
impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
|
impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
|
||||||
fn with<F>(&mut self, wrap_scope: Scope<'_>, f: F)
|
fn with<F>(&mut self, wrap_scope: Scope<'_>, f: F)
|
||||||
where
|
where
|
||||||
F: for<'b> FnOnce(ScopeRef<'_>, &mut LifetimeContext<'b, 'tcx>),
|
F: for<'b> FnOnce(&mut LifetimeContext<'b, 'tcx>),
|
||||||
{
|
{
|
||||||
let LifetimeContext { tcx, map, .. } = self;
|
let LifetimeContext { tcx, map, .. } = self;
|
||||||
let labels_in_fn = take(&mut self.labels_in_fn);
|
|
||||||
let xcrate_object_lifetime_defaults = take(&mut self.xcrate_object_lifetime_defaults);
|
let xcrate_object_lifetime_defaults = take(&mut self.xcrate_object_lifetime_defaults);
|
||||||
let missing_named_lifetime_spots = take(&mut self.missing_named_lifetime_spots);
|
let missing_named_lifetime_spots = take(&mut self.missing_named_lifetime_spots);
|
||||||
let mut this = LifetimeContext {
|
let mut this = LifetimeContext {
|
||||||
|
@ -1785,16 +1620,14 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
|
||||||
map,
|
map,
|
||||||
scope: &wrap_scope,
|
scope: &wrap_scope,
|
||||||
trait_definition_only: self.trait_definition_only,
|
trait_definition_only: self.trait_definition_only,
|
||||||
labels_in_fn,
|
|
||||||
xcrate_object_lifetime_defaults,
|
xcrate_object_lifetime_defaults,
|
||||||
missing_named_lifetime_spots,
|
missing_named_lifetime_spots,
|
||||||
};
|
};
|
||||||
let span = tracing::debug_span!("scope", scope = ?TruncatedScopeDebug(&this.scope));
|
let span = tracing::debug_span!("scope", scope = ?TruncatedScopeDebug(&this.scope));
|
||||||
{
|
{
|
||||||
let _enter = span.enter();
|
let _enter = span.enter();
|
||||||
f(self.scope, &mut this);
|
f(&mut this);
|
||||||
}
|
}
|
||||||
self.labels_in_fn = this.labels_in_fn;
|
|
||||||
self.xcrate_object_lifetime_defaults = this.xcrate_object_lifetime_defaults;
|
self.xcrate_object_lifetime_defaults = this.xcrate_object_lifetime_defaults;
|
||||||
self.missing_named_lifetime_spots = this.missing_named_lifetime_spots;
|
self.missing_named_lifetime_spots = this.missing_named_lifetime_spots;
|
||||||
}
|
}
|
||||||
|
@ -1891,10 +1724,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
|
||||||
scope_type: BinderScopeType::Normal,
|
scope_type: BinderScopeType::Normal,
|
||||||
allow_late_bound: true,
|
allow_late_bound: true,
|
||||||
};
|
};
|
||||||
self.with(scope, move |old_scope, this| {
|
self.with(scope, walk);
|
||||||
this.check_lifetime_params(old_scope, &generics.params);
|
|
||||||
walk(this);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn next_early_index_helper(&self, only_opaque_type_parent: bool) -> u32 {
|
fn next_early_index_helper(&self, only_opaque_type_parent: bool) -> u32 {
|
||||||
|
@ -2165,7 +1995,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
|
||||||
GenericArg::Type(ty) => {
|
GenericArg::Type(ty) => {
|
||||||
if let Some(<) = object_lifetime_defaults.get(i) {
|
if let Some(<) = object_lifetime_defaults.get(i) {
|
||||||
let scope = Scope::ObjectLifetimeDefault { lifetime: lt, s: self.scope };
|
let scope = Scope::ObjectLifetimeDefault { lifetime: lt, s: self.scope };
|
||||||
self.with(scope, |_, this| this.visit_ty(ty));
|
self.with(scope, |this| this.visit_ty(ty));
|
||||||
} else {
|
} else {
|
||||||
self.visit_ty(ty);
|
self.visit_ty(ty);
|
||||||
}
|
}
|
||||||
|
@ -2222,15 +2052,15 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
|
||||||
type_def_id,
|
type_def_id,
|
||||||
binding.ident,
|
binding.ident,
|
||||||
);
|
);
|
||||||
self.with(scope, |_, this| {
|
self.with(scope, |this| {
|
||||||
let scope = Scope::Supertrait {
|
let scope = Scope::Supertrait {
|
||||||
lifetimes: lifetimes.unwrap_or_default(),
|
lifetimes: lifetimes.unwrap_or_default(),
|
||||||
s: this.scope,
|
s: this.scope,
|
||||||
};
|
};
|
||||||
this.with(scope, |_, this| this.visit_assoc_type_binding(binding));
|
this.with(scope, |this| this.visit_assoc_type_binding(binding));
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
self.with(scope, |_, this| this.visit_assoc_type_binding(binding));
|
self.with(scope, |this| this.visit_assoc_type_binding(binding));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2346,7 +2176,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
|
||||||
elide: Elide::FreshLateAnon(named_late_bound_vars, Cell::new(0)),
|
elide: Elide::FreshLateAnon(named_late_bound_vars, Cell::new(0)),
|
||||||
s: self.scope,
|
s: self.scope,
|
||||||
};
|
};
|
||||||
self.with(arg_scope, |_, this| {
|
self.with(arg_scope, |this| {
|
||||||
for input in inputs {
|
for input in inputs {
|
||||||
this.visit_ty(input);
|
this.visit_ty(input);
|
||||||
}
|
}
|
||||||
|
@ -2466,7 +2296,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
|
||||||
visitor.visit_ty(&inputs[0]);
|
visitor.visit_ty(&inputs[0]);
|
||||||
if let Set1::One(lifetime) = visitor.lifetime {
|
if let Set1::One(lifetime) = visitor.lifetime {
|
||||||
let scope = Scope::Elision { elide: Elide::Exact(lifetime), s: self.scope };
|
let scope = Scope::Elision { elide: Elide::Exact(lifetime), s: self.scope };
|
||||||
self.with(scope, |_, this| this.visit_ty(output));
|
self.with(scope, |this| this.visit_ty(output));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2517,7 +2347,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
|
||||||
debug!(?elide);
|
debug!(?elide);
|
||||||
|
|
||||||
let scope = Scope::Elision { elide, s: self.scope };
|
let scope = Scope::Elision { elide, s: self.scope };
|
||||||
self.with(scope, |_, this| this.visit_ty(output));
|
self.with(scope, |this| this.visit_ty(output));
|
||||||
|
|
||||||
struct GatherLifetimes<'a> {
|
struct GatherLifetimes<'a> {
|
||||||
map: &'a NamedRegionMap,
|
map: &'a NamedRegionMap,
|
||||||
|
@ -2789,101 +2619,6 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
|
||||||
self.insert_lifetime(lifetime_ref, lifetime.shifted(late_depth));
|
self.insert_lifetime(lifetime_ref, lifetime.shifted(late_depth));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_lifetime_params(
|
|
||||||
&mut self,
|
|
||||||
old_scope: ScopeRef<'_>,
|
|
||||||
params: &'tcx [hir::GenericParam<'tcx>],
|
|
||||||
) {
|
|
||||||
let lifetimes: Vec<_> = params
|
|
||||||
.iter()
|
|
||||||
.filter_map(|param| match param.kind {
|
|
||||||
GenericParamKind::Lifetime { .. } => {
|
|
||||||
Some((param, param.name.normalize_to_macros_2_0()))
|
|
||||||
}
|
|
||||||
_ => None,
|
|
||||||
})
|
|
||||||
.collect();
|
|
||||||
for (i, (lifetime_i, lifetime_i_name)) in lifetimes.iter().enumerate() {
|
|
||||||
if let hir::ParamName::Plain(_) = lifetime_i_name {
|
|
||||||
let name = lifetime_i_name.ident().name;
|
|
||||||
if name == kw::UnderscoreLifetime || name == kw::StaticLifetime {
|
|
||||||
self.tcx.sess.delay_span_bug(
|
|
||||||
lifetime_i.span,
|
|
||||||
&format!("invalid lifetime parameter name: `{}`", lifetime_i.name.ident()),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// It is a hard error to shadow a lifetime within the same scope.
|
|
||||||
for (lifetime_j, lifetime_j_name) in lifetimes.iter().skip(i + 1) {
|
|
||||||
if lifetime_i_name == lifetime_j_name {
|
|
||||||
struct_span_err!(
|
|
||||||
self.tcx.sess,
|
|
||||||
lifetime_j.span,
|
|
||||||
E0263,
|
|
||||||
"lifetime name `{}` declared twice in the same scope",
|
|
||||||
lifetime_j.name.ident()
|
|
||||||
)
|
|
||||||
.span_label(lifetime_j.span, "declared twice")
|
|
||||||
.span_label(lifetime_i.span, "previous declaration here")
|
|
||||||
.emit();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// It is a soft error to shadow a lifetime within a parent scope.
|
|
||||||
self.check_lifetime_param_for_shadowing(old_scope, &lifetime_i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn check_lifetime_param_for_shadowing(
|
|
||||||
&self,
|
|
||||||
mut old_scope: ScopeRef<'_>,
|
|
||||||
param: &'tcx hir::GenericParam<'tcx>,
|
|
||||||
) {
|
|
||||||
for label in &self.labels_in_fn {
|
|
||||||
// FIXME (#24278): non-hygienic comparison
|
|
||||||
if param.name.ident().name == label.name {
|
|
||||||
signal_shadowing_problem(
|
|
||||||
self.tcx,
|
|
||||||
label.name,
|
|
||||||
original_label(label.span),
|
|
||||||
shadower_lifetime(¶m),
|
|
||||||
);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
loop {
|
|
||||||
match *old_scope {
|
|
||||||
Scope::Body { s, .. }
|
|
||||||
| Scope::Elision { s, .. }
|
|
||||||
| Scope::ObjectLifetimeDefault { s, .. }
|
|
||||||
| Scope::Supertrait { s, .. }
|
|
||||||
| Scope::TraitRefBoundary { s, .. } => {
|
|
||||||
old_scope = s;
|
|
||||||
}
|
|
||||||
|
|
||||||
Scope::Root => {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Scope::Binder { ref lifetimes, s, .. } => {
|
|
||||||
if let Some(&def) = lifetimes.get(¶m.name.normalize_to_macros_2_0()) {
|
|
||||||
signal_shadowing_problem(
|
|
||||||
self.tcx,
|
|
||||||
param.name.ident().name,
|
|
||||||
original_lifetime(self.tcx.def_span(def.id().unwrap())),
|
|
||||||
shadower_lifetime(¶m),
|
|
||||||
);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
old_scope = s;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[tracing::instrument(level = "debug", skip(self))]
|
#[tracing::instrument(level = "debug", skip(self))]
|
||||||
fn insert_lifetime(&mut self, lifetime_ref: &'tcx hir::Lifetime, def: Region) {
|
fn insert_lifetime(&mut self, lifetime_ref: &'tcx hir::Lifetime, def: Region) {
|
||||||
debug!(
|
debug!(
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue