Skip to content

Commit

Permalink
resolve: Prevent fresh bindings from shadowing ambiguity items
Browse files Browse the repository at this point in the history
Correctly treat const generic parameters in fresh binding disambiguation
  • Loading branch information
petrochenkov committed Mar 15, 2020
1 parent 7cdbc87 commit 78f01ec
Show file tree
Hide file tree
Showing 9 changed files with 123 additions and 24 deletions.
3 changes: 3 additions & 0 deletions src/librustc_mir_build/hair/pattern/check_match.rs
Expand Up @@ -87,6 +87,9 @@ impl PatCtxt<'_, '_> {
PatternError::AssocConstInPattern(span) => {
self.span_e0158(span, "associated consts cannot be referenced in patterns")
}
PatternError::ConstParamInPattern(span) => {
self.span_e0158(span, "const parameters cannot be referenced in patterns")
}
PatternError::FloatBug => {
// FIXME(#31407) this is only necessary because float parsing is buggy
::rustc::mir::interpret::struct_error(
Expand Down
7 changes: 6 additions & 1 deletion src/librustc_mir_build/hair/pattern/mod.rs
Expand Up @@ -31,6 +31,7 @@ use std::fmt;
#[derive(Clone, Debug)]
crate enum PatternError {
AssocConstInPattern(Span),
ConstParamInPattern(Span),
StaticInPattern(Span),
FloatBug,
NonConstPath(Span),
Expand Down Expand Up @@ -727,7 +728,11 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
| Res::SelfCtor(..) => PatKind::Leaf { subpatterns },

_ => {
self.errors.push(PatternError::NonConstPath(span));
let pattern_error = match res {
Res::Def(DefKind::ConstParam, _) => PatternError::ConstParamInPattern(span),
_ => PatternError::NonConstPath(span),
};
self.errors.push(pattern_error);
PatKind::Wild
}
};
Expand Down
39 changes: 24 additions & 15 deletions src/librustc_resolve/late.rs
Expand Up @@ -1517,21 +1517,33 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
ident: Ident,
has_sub: bool,
) -> Option<Res> {
let binding =
self.resolve_ident_in_lexical_scope(ident, ValueNS, None, pat.span)?.item()?;
let res = binding.res();
let ls_binding = self.resolve_ident_in_lexical_scope(ident, ValueNS, None, pat.span)?;
let (res, binding) = match ls_binding {
LexicalScopeBinding::Item(binding) if binding.is_ambiguity() => {
// For ambiguous bindings we don't know all their definitions and cannot check
// whether they can be shadowed by fresh bindings or not, so force an error.
self.r.record_use(ident, ValueNS, binding, false);
return None;
}
LexicalScopeBinding::Item(binding) => (binding.res(), Some(binding)),
LexicalScopeBinding::Res(res) => (res, None),
};

// An immutable (no `mut`) by-value (no `ref`) binding pattern without
// a sub pattern (no `@ $pat`) is syntactically ambiguous as it could
// also be interpreted as a path to e.g. a constant, variant, etc.
let is_syntactic_ambiguity = !has_sub && bm == BindingMode::ByValue(Mutability::Not);

match res {
Res::Def(DefKind::Ctor(_, CtorKind::Const), _) | Res::Def(DefKind::Const, _)
Res::Def(DefKind::Ctor(_, CtorKind::Const), _)
| Res::Def(DefKind::Const, _)
| Res::Def(DefKind::ConstParam, _)
if is_syntactic_ambiguity =>
{
// Disambiguate in favor of a unit struct/variant or constant pattern.
self.r.record_use(ident, ValueNS, binding, false);
if let Some(binding) = binding {
self.r.record_use(ident, ValueNS, binding, false);
}
Some(res)
}
Res::Def(DefKind::Ctor(..), _)
Expand All @@ -1547,23 +1559,20 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
ResolutionError::BindingShadowsSomethingUnacceptable(
pat_src.descr(),
ident.name,
binding,
binding.expect("no binding for a ctor or static"),
),
);
None
}
Res::Def(DefKind::Fn, _) | Res::Err => {
Res::Def(DefKind::Fn, _) | Res::Local(..) | Res::Err => {
// These entities are explicitly allowed to be shadowed by fresh bindings.
None
}
res => {
span_bug!(
ident.span,
"unexpected resolution for an \
identifier in pattern: {:?}",
res
);
}
_ => span_bug!(
ident.span,
"unexpected resolution for an identifier in pattern: {:?}",
res
),
}
}

Expand Down
7 changes: 0 additions & 7 deletions src/librustc_resolve/lib.rs
Expand Up @@ -323,13 +323,6 @@ enum LexicalScopeBinding<'a> {
}

impl<'a> LexicalScopeBinding<'a> {
fn item(self) -> Option<&'a NameBinding<'a>> {
match self {
LexicalScopeBinding::Item(binding) => Some(binding),
_ => None,
}
}

fn res(self) -> Res {
match self {
LexicalScopeBinding::Item(binding) => binding.res(),
Expand Down
3 changes: 2 additions & 1 deletion src/librustc_typeck/check/pat.rs
Expand Up @@ -716,7 +716,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
Res::Def(DefKind::Ctor(_, CtorKind::Const), _)
| Res::SelfCtor(..)
| Res::Def(DefKind::Const, _)
| Res::Def(DefKind::AssocConst, _) => {} // OK
| Res::Def(DefKind::AssocConst, _)
| Res::Def(DefKind::ConstParam, _) => {} // OK
_ => bug!("unexpected pattern resolution: {:?}", res),
}

Expand Down
18 changes: 18 additions & 0 deletions src/test/ui/binding/ambiguity-item.rs
@@ -0,0 +1,18 @@
// Identifier pattern referring to an ambiguity item is an error (issue #46079).

mod m {
pub fn f() {}
}
use m::*;

mod n {
pub fn f() {}
}
use n::*; // OK, no conflict with `use m::*;`

fn main() {
let v = f; //~ ERROR `f` is ambiguous
match v {
f => {} //~ ERROR `f` is ambiguous
}
}
41 changes: 41 additions & 0 deletions src/test/ui/binding/ambiguity-item.stderr
@@ -0,0 +1,41 @@
error[E0659]: `f` is ambiguous (glob import vs glob import in the same module)
--> $DIR/ambiguity-item.rs:14:13
|
LL | let v = f;
| ^ ambiguous name
|
note: `f` could refer to the function imported here
--> $DIR/ambiguity-item.rs:6:5
|
LL | use m::*;
| ^^^^
= help: consider adding an explicit import of `f` to disambiguate
note: `f` could also refer to the function imported here
--> $DIR/ambiguity-item.rs:11:5
|
LL | use n::*; // OK, no conflict with `use m::*;`
| ^^^^
= help: consider adding an explicit import of `f` to disambiguate

error[E0659]: `f` is ambiguous (glob import vs glob import in the same module)
--> $DIR/ambiguity-item.rs:16:9
|
LL | f => {}
| ^ ambiguous name
|
note: `f` could refer to the function imported here
--> $DIR/ambiguity-item.rs:6:5
|
LL | use m::*;
| ^^^^
= help: consider adding an explicit import of `f` to disambiguate
note: `f` could also refer to the function imported here
--> $DIR/ambiguity-item.rs:11:5
|
LL | use n::*; // OK, no conflict with `use m::*;`
| ^^^^
= help: consider adding an explicit import of `f` to disambiguate

error: aborting due to 2 previous errors

For more information about this error, try `rustc --explain E0659`.
12 changes: 12 additions & 0 deletions src/test/ui/binding/const-param.rs
@@ -0,0 +1,12 @@
// Identifier pattern referring to a const generic parameter is an error (issue #68853).

#![feature(const_generics)] //~ WARN the feature `const_generics` is incomplete

fn check<const N: usize>() {
match 1 {
N => {} //~ ERROR const parameters cannot be referenced in patterns
_ => {}
}
}

fn main() {}
17 changes: 17 additions & 0 deletions src/test/ui/binding/const-param.stderr
@@ -0,0 +1,17 @@
warning: the feature `const_generics` is incomplete and may cause the compiler to crash
--> $DIR/const-param.rs:3:12
|
LL | #![feature(const_generics)]
| ^^^^^^^^^^^^^^
|
= note: `#[warn(incomplete_features)]` on by default

error[E0158]: const parameters cannot be referenced in patterns
--> $DIR/const-param.rs:7:9
|
LL | N => {}
| ^

error: aborting due to previous error

For more information about this error, try `rustc --explain E0158`.

0 comments on commit 78f01ec

Please sign in to comment.