Skip to content

Commit 7e59f02

Browse files
rchen152meta-codesync[bot]
authored andcommitted
Expand type alias redefinition check
Summary: Expands the type alias redefinition check added in D92188517: * we now do the check in both directions (redefining something as a type alias, or redefining a type alias as something else) * we also check legacy type aliases and ones created via `TypeAliasType(...)` * we only error on redefinitions in the same scope (this matches pyright's behavior) Reviewed By: stroxler Differential Revision: D92904394 fbshipit-source-id: 177aeaf5b234ffd2b035b35f0033b961e2af5134
1 parent 62c0e0d commit 7e59f02

File tree

5 files changed

+82
-18
lines changed

5 files changed

+82
-18
lines changed

conformance/third_party/conformance.exp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -947,8 +947,8 @@
947947
{
948948
"code": -2,
949949
"column": 6,
950-
"concise_description": "Cannot redefine existing name `BadTypeAlias14` as a type alias",
951-
"description": "Cannot redefine existing name `BadTypeAlias14` as a type alias",
950+
"concise_description": "Cannot redefine existing type alias `BadTypeAlias14`",
951+
"description": "Cannot redefine existing type alias `BadTypeAlias14`",
952952
"line": 52,
953953
"name": "redefinition",
954954
"severity": "error",

pyrefly/lib/binding/bindings.rs

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1334,6 +1334,7 @@ impl<'a> BindingsBuilder<'a> {
13341334
idx: Idx<Key>,
13351335
style: FlowStyle,
13361336
) -> Option<Idx<KeyAnnotation>> {
1337+
self.check_for_type_alias_redefinition(name, idx);
13371338
let name = Hashed::new(name);
13381339
let write_info = self
13391340
.scopes
@@ -1351,6 +1352,28 @@ impl<'a> BindingsBuilder<'a> {
13511352
write_info.annotation
13521353
}
13531354

1355+
fn check_for_type_alias_redefinition(&self, name: &Name, idx: Idx<Key>) {
1356+
let prev_idx = self.scopes.current_flow_idx(name);
1357+
if let Some(prev_idx) = prev_idx {
1358+
if matches!(
1359+
self.idx_to_binding(prev_idx),
1360+
Some(Binding::TypeAlias { .. })
1361+
) {
1362+
self.error(
1363+
self.idx_to_key(idx).range(),
1364+
ErrorInfo::Kind(ErrorKind::Redefinition),
1365+
format!("Cannot redefine existing type alias `{name}`",),
1366+
)
1367+
} else if matches!(self.idx_to_binding(idx), Some(Binding::TypeAlias { .. })) {
1368+
self.error(
1369+
self.idx_to_key(idx).range(),
1370+
ErrorInfo::Kind(ErrorKind::Redefinition),
1371+
format!("Cannot redefine existing name `{name}` as a type alias",),
1372+
);
1373+
}
1374+
}
1375+
}
1376+
13541377
pub fn type_params(&mut self, x: &mut TypeParams) -> SmallSet<Name> {
13551378
let mut names = SmallSet::new();
13561379
for x in x.type_params.iter_mut() {

pyrefly/lib/binding/scope.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1748,6 +1748,14 @@ impl Scopes {
17481748
Some(self.current().flow.get_info(name)?.value()?.style.clone())
17491749
}
17501750

1751+
/// Get the flow idx for `name` in the current scope.
1752+
///
1753+
/// Returns `None` if there is no current flow (which may mean the
1754+
/// name is uninitialized in the current scope, or is not in scope at all).
1755+
pub fn current_flow_idx(&self, name: &Name) -> Option<Idx<Key>> {
1756+
Some(self.current().flow.get_info(name)?.value()?.idx)
1757+
}
1758+
17511759
/// Return the current binding index and flow style for `name`, if it exists
17521760
/// in any enclosing scope.
17531761
pub fn binding_idx_for_name(&self, name: &Name) -> Option<(Idx<Key>, FlowStyle)> {

pyrefly/lib/binding/stmt.rs

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,6 @@ use crate::binding::narrow::NarrowOps;
5858
use crate::binding::narrow::NarrowingSubject;
5959
use crate::binding::scope::FlowStyle;
6060
use crate::binding::scope::LoopExit;
61-
use crate::binding::scope::NameReadInfo;
6261
use crate::binding::scope::Scope;
6362
use crate::config::error_kind::ErrorKind;
6463
use crate::error::context::ErrorInfo;
@@ -829,19 +828,6 @@ impl<'a> BindingsBuilder<'a> {
829828
);
830829
}
831830
if let Expr::Name(name) = *x.name {
832-
if let NameReadInfo::Flow { .. } = self
833-
.scopes
834-
.look_up_name_for_read(Hashed::new(&name.id), &Usage::StaticTypeInformation)
835-
{
836-
self.error(
837-
name.range(),
838-
ErrorInfo::Kind(ErrorKind::Redefinition),
839-
format!(
840-
"Cannot redefine existing name `{}` as a type alias",
841-
name.id
842-
),
843-
);
844-
}
845831
// Create a new scope for the type alias type parameters
846832
self.scopes.push(Scope::type_alias(x.range));
847833
if let Some(params) = &mut x.type_params {

pyrefly/lib/test/type_alias.rs

Lines changed: 49 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1141,14 +1141,61 @@ testcase!(
11411141
test_type_statement_redeclaration_conformance,
11421142
r#"
11431143
type BadTypeAlias14 = int
1144-
type BadTypeAlias14 = int # E: Cannot redefine existing name `BadTypeAlias14` as a type alias
1144+
type BadTypeAlias14 = int # E: Cannot redefine existing type alias `BadTypeAlias14`
11451145
11461146
class C:
11471147
type T = int
1148-
type T = int # E: Cannot redefine existing name `T` as a type alias
1148+
type T = int # E: Cannot redefine existing type alias `T`
11491149
"#,
11501150
);
11511151

1152+
testcase!(
1153+
test_redeclare_type_alias_as_non_type_alias,
1154+
r#"
1155+
type BadTypeAlias14 = int
1156+
BadTypeAlias14 = 0 # E: Cannot redefine existing type alias `BadTypeAlias14`
1157+
"#,
1158+
);
1159+
1160+
testcase!(
1161+
test_redeclare_non_type_alias_as_type_alias,
1162+
r#"
1163+
BadTypeAlias14 = 0
1164+
type BadTypeAlias14 = int # E: Cannot redefine existing name `BadTypeAlias14` as a type alias
1165+
"#,
1166+
);
1167+
1168+
testcase!(
1169+
test_redeclare_legacy_type_alias,
1170+
r#"
1171+
from typing import TypeAlias, Union
1172+
1173+
X1: TypeAlias = int
1174+
X1 = 0 # E: Cannot redefine existing type alias `X1`
1175+
1176+
X2 = Union[int, str]
1177+
X2 = 0 # E: Cannot redefine existing type alias `X2`
1178+
"#,
1179+
);
1180+
1181+
testcase!(
1182+
test_redeclare_typealiastype,
1183+
r#"
1184+
from typing import TypeAliasType
1185+
X = TypeAliasType("X", int)
1186+
X = 0 # E: Cannot redefine existing type alias `X`
1187+
"#,
1188+
);
1189+
1190+
testcase!(
1191+
test_redeclare_type_alias_in_nested_scope_ok,
1192+
r#"
1193+
type X = int
1194+
class C:
1195+
type X = str
1196+
"#,
1197+
);
1198+
11521199
testcase!(
11531200
test_display_instance_vs_type,
11541201
r#"

0 commit comments

Comments
 (0)