Skip to content

Commit 944e041

Browse files
yangdanny97meta-codesync[bot]
authored andcommitted
populate display name when untyping a type alias (facebook#1641)
Summary: Pull Request resolved: facebook#1641 - populate display name when untyping a union - keep name when simplifying - display the expanded type when the top level type being printed is the alias (only use the display name for nested types) Differential Revision: D87558543
1 parent f6ffae7 commit 944e041

File tree

8 files changed

+90
-16
lines changed

8 files changed

+90
-16
lines changed

conformance/third_party/conformance.exp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,8 @@
1515
{
1616
"code": -2,
1717
"column": 9,
18-
"concise_description": "`TypeAlias[GoodTypeAlias3, type[list[int | None]]]` is not subscriptable",
19-
"description": "`TypeAlias[GoodTypeAlias3, type[list[int | None]]]` is not subscriptable",
18+
"concise_description": "`TypeAlias[GoodTypeAlias3, type[list[GoodTypeAlias2]]]` is not subscriptable",
19+
"description": "`TypeAlias[GoodTypeAlias3, type[list[GoodTypeAlias2]]]` is not subscriptable",
2020
"line": 68,
2121
"name": "unsupported-operation",
2222
"severity": "error",
@@ -270,8 +270,8 @@
270270
{
271271
"code": -2,
272272
"column": 9,
273-
"concise_description": "`type[list[int | None]]` is not subscriptable",
274-
"description": "`type[list[int | None]]` is not subscriptable",
273+
"concise_description": "`type[list[GoodTypeAlias2]]` is not subscriptable",
274+
"description": "`type[list[GoodTypeAlias2]]` is not subscriptable",
275275
"line": 77,
276276
"name": "unsupported-operation",
277277
"severity": "error",

crates/pyrefly_types/src/display.rs

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -415,8 +415,8 @@ impl<'a> TypeDisplayContext<'a> {
415415
Type::Union(box (types, _)) if types.is_empty() => {
416416
self.maybe_fmt_with_module("typing", "Never", output)
417417
}
418-
Type::Union(box (_, Some(name))) => output.write_str(name),
419-
Type::Union(box (types, None)) => {
418+
Type::Union(box (_, Some(name))) if !is_toplevel => output.write_str(name),
419+
Type::Union(box (types, _)) => {
420420
// All Literals will be collected into a single Literal at the index of the first Literal.
421421
let mut literal_idx = None;
422422
let mut literals = Vec::new();
@@ -1100,13 +1100,24 @@ pub mod tests {
11001100
Type::union(vec![nonlit1.clone(), lit1, nonlit2.clone(), lit2]).to_string(),
11011101
"None | Literal[True, 'test'] | LiteralString"
11021102
);
1103+
1104+
// Unions have an optional name field, which is shown only when
1105+
// the union is nested in another type
11031106
assert_eq!(
11041107
Type::Union(Box::new((
1105-
vec![nonlit1, nonlit2],
1108+
vec![nonlit1.clone(), nonlit2.clone()],
11061109
Some("MyUnion".to_owned())
11071110
)))
11081111
.to_string(),
1109-
"MyUnion"
1112+
"None | LiteralString"
1113+
);
1114+
assert_eq!(
1115+
Type::Type(Box::new(Type::Union(Box::new((
1116+
vec![nonlit1, nonlit2],
1117+
Some("MyUnion".to_owned())
1118+
)))))
1119+
.to_string(),
1120+
"type[MyUnion]"
11101121
);
11111122
}
11121123

crates/pyrefly_types/src/types.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1422,10 +1422,11 @@ impl Type {
14221422
})
14231423
}
14241424

1425-
pub fn sort_unions(self) -> Self {
1425+
pub fn sort_unions_and_drop_names(self) -> Self {
14261426
self.transform(&mut |ty| {
1427-
if let Type::Union(box (ts, _)) = ty {
1427+
if let Type::Union(box (ts, name)) = ty {
14281428
ts.sort();
1429+
*name = None;
14291430
}
14301431
})
14311432
}

pyrefly/lib/alt/solve.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3751,7 +3751,13 @@ impl<'a, Ans: LookupAnswer> AnswersSolver<'a, Ans> {
37513751
Type::None => Some(Type::None), // Both a value and a type
37523752
Type::Ellipsis => Some(Type::Ellipsis), // A bit weird because of tuples, so just promote it
37533753
Type::Any(style) => Some(style.propagate()),
3754-
Type::TypeAlias(ta) => self.untype_opt(ta.as_type(), range, errors),
3754+
Type::TypeAlias(ta) => {
3755+
let mut aliased_type = self.untype_opt(ta.as_type(), range, errors)?;
3756+
if let Type::Union(box (_, name)) = &mut aliased_type {
3757+
*name = Some(ta.name.to_string());
3758+
}
3759+
Some(aliased_type)
3760+
}
37553761
t @ Type::Unpack(
37563762
box Type::Tuple(_) | box Type::TypeVarTuple(_) | box Type::Quantified(_),
37573763
) => Some(t),

pyrefly/lib/alt/special_calls.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,8 +69,9 @@ impl<'a, Ans: LookupAnswer> AnswersSolver<'a, Ans> {
6969
.distribute_type_over_union();
7070
// Make assert_type(Self@SomeClass, typing.Self) work.
7171
ty.subst_self_type_mut(&self_form);
72-
// Re-sort unions. Make sure to keep this as the final step before comparison.
73-
ty.sort_unions()
72+
// Re-sort unions & drop any display names.
73+
// Make sure to keep this as the final step before comparison.
74+
ty.sort_unions_and_drop_names()
7475
};
7576
let a = normalize_type(a, expr_a);
7677
let b = normalize_type(b, expr_b);

pyrefly/lib/solver/solver.rs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -456,8 +456,13 @@ impl Solver {
456456
/// Simplify a type as much as we can.
457457
fn simplify_mut(&self, t: &mut Type) {
458458
t.transform_mut(&mut |x| {
459-
if let Type::Union(box (xs, _)) = x {
460-
*x = unions(mem::take(xs));
459+
if let Type::Union(box (xs, original_name)) = x {
460+
let mut merged = unions(mem::take(xs));
461+
// Preserve union display names during simplification
462+
if let Type::Union(box (_, name)) = &mut merged {
463+
*name = original_name.clone();
464+
}
465+
*x = merged;
461466
}
462467
if let Type::Intersect(y) = x {
463468
*x = intersect(mem::take(&mut y.0), y.1.clone());

pyrefly/lib/test/class_overrides.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -577,7 +577,7 @@ class A:
577577
def f(self, x: TA1):
578578
pass
579579
class B(A):
580-
def f(self, x: TA2): # E: `B.f` has type `BoundMethod[B, (self: B, x: float | int) -> None]`, which is not assignable to `BoundMethod[B, (self: B, x: float | int | None) -> None]`, the type of `A.f`
580+
def f(self, x: TA2): # E: `B.f` has type `BoundMethod[B, (self: B, x: TA2) -> None]`, which is not assignable to `BoundMethod[B, (self: B, x: TA1) -> None]`, the type of `A.f`
581581
pass
582582
"#,
583583
);

pyrefly/lib/test/type_alias.rs

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -806,3 +806,53 @@ x1: Spam1[int, str] = int
806806
x2: Spam2[int, str] = int
807807
"#,
808808
);
809+
810+
fn env_with_alias() -> TestEnv {
811+
TestEnv::one(
812+
"foo",
813+
r#"
814+
type TA = int | str
815+
816+
def f(x: TA) -> TA:
817+
return x
818+
"#,
819+
)
820+
}
821+
822+
testcase!(
823+
test_alias_union_name,
824+
env_with_alias(),
825+
r#"
826+
from foo import TA, f
827+
from typing import Callable
828+
829+
val1: int | str = 1
830+
val2: TA = 1
831+
832+
# Union names are only shown when nested in another type
833+
834+
f(object()) # E: Argument `object` is not assignable to parameter `x` with type `int | str` in function `foo.f`
835+
f(val1)
836+
f(val2)
837+
x1: TA = object() # E: `object` is not assignable to `int | str`
838+
x2: TA = val1
839+
x3: TA = val2
840+
c1: Callable[[int], int] = f # E: `(x: TA) -> TA` is not assignable to `(int) -> int`
841+
842+
# Union names are lost when flattened into another union
843+
844+
class C: pass
845+
def f2(x: TA | C) -> TA | C:
846+
return x
847+
848+
f2(object()) # E: Argument `object` is not assignable to parameter `x` with type `C | int | str` in function `f2`
849+
f2(val1)
850+
f2(val2)
851+
f2(C())
852+
x4: TA | C = object() # E: `object` is not assignable to `C | int | str`
853+
x5: TA | C = val1
854+
x6: TA | C = val2
855+
x7: TA | C = C()
856+
c2: Callable[[int], int] = f2 # E: `(x: C | int | str) -> C | int | str` is not assignable to `(int) -> int`
857+
"#,
858+
);

0 commit comments

Comments
 (0)