Skip to content

Only walk ribs to collect possibly shadowed params if we are adding params in our new rib #128550

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Aug 8, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
201 changes: 105 additions & 96 deletions compiler/rustc_resolve/src/late.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2667,119 +2667,128 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
let mut function_type_rib = Rib::new(kind);
let mut function_value_rib = Rib::new(kind);
let mut function_lifetime_rib = LifetimeRib::new(lifetime_kind);
let mut seen_bindings = FxHashMap::default();
// Store all seen lifetimes names from outer scopes.
let mut seen_lifetimes = FxHashSet::default();

// We also can't shadow bindings from associated parent items.
for ns in [ValueNS, TypeNS] {
for parent_rib in self.ribs[ns].iter().rev() {
seen_bindings.extend(parent_rib.bindings.keys().map(|ident| (*ident, ident.span)));

// Break at mod level, to account for nested items which are
// allowed to shadow generic param names.
if matches!(parent_rib.kind, RibKind::Module(..)) {
break;
}
}
}

// Forbid shadowing lifetime bindings
for rib in self.lifetime_ribs.iter().rev() {
seen_lifetimes.extend(rib.bindings.iter().map(|(ident, _)| *ident));
if let LifetimeRibKind::Item = rib.kind {
break;
// Only check for shadowed bindings if we're declaring new params.
if !params.is_empty() {
let mut seen_bindings = FxHashMap::default();
// Store all seen lifetimes names from outer scopes.
let mut seen_lifetimes = FxHashSet::default();

// We also can't shadow bindings from associated parent items.
for ns in [ValueNS, TypeNS] {
for parent_rib in self.ribs[ns].iter().rev() {
seen_bindings
.extend(parent_rib.bindings.keys().map(|ident| (*ident, ident.span)));

// Break at mod level, to account for nested items which are
// allowed to shadow generic param names.
if matches!(parent_rib.kind, RibKind::Module(..)) {
break;
}
}
}
}

for param in params {
let ident = param.ident.normalize_to_macros_2_0();
debug!("with_generic_param_rib: {}", param.id);

if let GenericParamKind::Lifetime = param.kind
&& let Some(&original) = seen_lifetimes.get(&ident)
{
diagnostics::signal_lifetime_shadowing(self.r.tcx.sess, original, param.ident);
// Record lifetime res, so lowering knows there is something fishy.
self.record_lifetime_param(param.id, LifetimeRes::Error);
continue;
// Forbid shadowing lifetime bindings
for rib in self.lifetime_ribs.iter().rev() {
seen_lifetimes.extend(rib.bindings.iter().map(|(ident, _)| *ident));
if let LifetimeRibKind::Item = rib.kind {
break;
}
}

match seen_bindings.entry(ident) {
Entry::Occupied(entry) => {
let span = *entry.get();
let err = ResolutionError::NameAlreadyUsedInParameterList(ident.name, span);
self.report_error(param.ident.span, err);
let rib = match param.kind {
GenericParamKind::Lifetime => {
// Record lifetime res, so lowering knows there is something fishy.
self.record_lifetime_param(param.id, LifetimeRes::Error);
continue;
}
GenericParamKind::Type { .. } => &mut function_type_rib,
GenericParamKind::Const { .. } => &mut function_value_rib,
};
for param in params {
let ident = param.ident.normalize_to_macros_2_0();
debug!("with_generic_param_rib: {}", param.id);

// Taint the resolution in case of errors to prevent follow up errors in typeck
self.r.record_partial_res(param.id, PartialRes::new(Res::Err));
rib.bindings.insert(ident, Res::Err);
if let GenericParamKind::Lifetime = param.kind
&& let Some(&original) = seen_lifetimes.get(&ident)
{
diagnostics::signal_lifetime_shadowing(self.r.tcx.sess, original, param.ident);
// Record lifetime res, so lowering knows there is something fishy.
self.record_lifetime_param(param.id, LifetimeRes::Error);
continue;
}
Entry::Vacant(entry) => {
entry.insert(param.ident.span);
}
}

if param.ident.name == kw::UnderscoreLifetime {
self.r
.dcx()
.emit_err(errors::UnderscoreLifetimeIsReserved { span: param.ident.span });
// Record lifetime res, so lowering knows there is something fishy.
self.record_lifetime_param(param.id, LifetimeRes::Error);
continue;
}
match seen_bindings.entry(ident) {
Entry::Occupied(entry) => {
let span = *entry.get();
let err = ResolutionError::NameAlreadyUsedInParameterList(ident.name, span);
self.report_error(param.ident.span, err);
let rib = match param.kind {
GenericParamKind::Lifetime => {
// Record lifetime res, so lowering knows there is something fishy.
self.record_lifetime_param(param.id, LifetimeRes::Error);
continue;
}
GenericParamKind::Type { .. } => &mut function_type_rib,
GenericParamKind::Const { .. } => &mut function_value_rib,
};

if param.ident.name == kw::StaticLifetime {
self.r.dcx().emit_err(errors::StaticLifetimeIsReserved {
span: param.ident.span,
lifetime: param.ident,
});
// Record lifetime res, so lowering knows there is something fishy.
self.record_lifetime_param(param.id, LifetimeRes::Error);
continue;
}
// Taint the resolution in case of errors to prevent follow up errors in typeck
self.r.record_partial_res(param.id, PartialRes::new(Res::Err));
rib.bindings.insert(ident, Res::Err);
continue;
}
Entry::Vacant(entry) => {
entry.insert(param.ident.span);
}
}

let def_id = self.r.local_def_id(param.id);
if param.ident.name == kw::UnderscoreLifetime {
self.r
.dcx()
.emit_err(errors::UnderscoreLifetimeIsReserved { span: param.ident.span });
// Record lifetime res, so lowering knows there is something fishy.
self.record_lifetime_param(param.id, LifetimeRes::Error);
continue;
}

// Plain insert (no renaming).
let (rib, def_kind) = match param.kind {
GenericParamKind::Type { .. } => (&mut function_type_rib, DefKind::TyParam),
GenericParamKind::Const { .. } => (&mut function_value_rib, DefKind::ConstParam),
GenericParamKind::Lifetime => {
let res = LifetimeRes::Param { param: def_id, binder };
self.record_lifetime_param(param.id, res);
function_lifetime_rib.bindings.insert(ident, (param.id, res));
if param.ident.name == kw::StaticLifetime {
self.r.dcx().emit_err(errors::StaticLifetimeIsReserved {
span: param.ident.span,
lifetime: param.ident,
});
// Record lifetime res, so lowering knows there is something fishy.
self.record_lifetime_param(param.id, LifetimeRes::Error);
continue;
}
};

let res = match kind {
RibKind::Item(..) | RibKind::AssocItem => Res::Def(def_kind, def_id.to_def_id()),
RibKind::Normal => {
// FIXME(non_lifetime_binders): Stop special-casing
// const params to error out here.
if self.r.tcx.features().non_lifetime_binders
&& matches!(param.kind, GenericParamKind::Type { .. })
{
let def_id = self.r.local_def_id(param.id);

// Plain insert (no renaming).
let (rib, def_kind) = match param.kind {
GenericParamKind::Type { .. } => (&mut function_type_rib, DefKind::TyParam),
GenericParamKind::Const { .. } => {
(&mut function_value_rib, DefKind::ConstParam)
}
GenericParamKind::Lifetime => {
let res = LifetimeRes::Param { param: def_id, binder };
self.record_lifetime_param(param.id, res);
function_lifetime_rib.bindings.insert(ident, (param.id, res));
continue;
}
};

let res = match kind {
RibKind::Item(..) | RibKind::AssocItem => {
Res::Def(def_kind, def_id.to_def_id())
} else {
Res::Err
}
}
_ => span_bug!(param.ident.span, "Unexpected rib kind {:?}", kind),
};
self.r.record_partial_res(param.id, PartialRes::new(res));
rib.bindings.insert(ident, res);
RibKind::Normal => {
// FIXME(non_lifetime_binders): Stop special-casing
// const params to error out here.
if self.r.tcx.features().non_lifetime_binders
&& matches!(param.kind, GenericParamKind::Type { .. })
{
Res::Def(def_kind, def_id.to_def_id())
} else {
Res::Err
}
}
_ => span_bug!(param.ident.span, "Unexpected rib kind {:?}", kind),
};
self.r.record_partial_res(param.id, PartialRes::new(res));
rib.bindings.insert(ident, res);
}
}

self.lifetime_ribs.push(function_lifetime_rib);
Expand Down
Loading