Skip to content

aliases_implicit: implicit type aliases are detected by an uppercase-first-letter naming heuristic #411

Description

@MelbourneDeveloper

Split out of #408. Confirmed live on main @ da74283 and on the bidirectionaltype-inference branch.

The code

crates/basilisk-checker/src/rules/aliases_implicit.rs:405-408, in build_alias_info_map's implicit-alias pass:

// Heuristic: if the name starts with uppercase and the RHS is a type
// expression (name, subscript, or union), treat it as an implicit alias
let first_char = var.name.chars().next().unwrap_or('a');
if !first_char.is_ascii_uppercase() {
    continue;
}

A module-level assignment is recognised as an implicit type alias only if its name begins with an uppercase ASCII letter. Naming convention is load-bearing: it decides whether the binding enters alias_map at all, and therefore whether any downstream check sees it — parameterization, ParamSpec, bounds, and union instantiation.

Why it looks correct

The conformance file names every implicit alias GoodTypeAlias1GoodTypeAlias13, ListAlias, ListOrSetAlias. Uppercase-first holds for all of them. PEP 613 and PEP 695 impose no such requirement — the typing spec says nothing about the case of an alias's name.

Failing cases

Union instantiation, silently accepted:

list_or_set = list | set
list_or_set()   # should error: cannot instantiate a union alias

ListOrSetAlias() is caught (aliases_implicit.py:133); the identical construct with a lowercase name is not, because check_union_alias_instantiation looks the callee up in alias_map and the binding was never inserted.

Parameterization, silently accepted:

my_alias = list[int]
def f(x: my_alias[str]) -> None: ...   # already specialized — should error

Also non-ASCII: Ålias = list | set fails is_ascii_uppercase and is skipped, so the rule is inconsistent for any identifier outside ASCII, which Python permits.

Secondary — looks_like_type_expression

The companion gate at :529 is a character blacklist over RHS text:

!text.contains(['=', '+', '-', '*', '/', '%', '!', '~', '^', '&', '{', '}'])

It rejects any RHS containing those characters anywhere, including inside a string forward reference or a Literal[...] argument, and accepts anything else. It is a second textual heuristic stacked on the first.

Fix

Decide alias-hood from binding information the resolver already has — the assignment's target, its RHS expression node, and whether the RHS is a type expression — not from the spelling of the name. Both gates should be replaced by structural analysis of the Ruff AST, matching the approach now used in aliases_type_statement.rs.

Needs off-suite regression tests: every implicit alias in the conformance suite is uppercase-first, so no suite case can detect this.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    spec-violationCode functionality/logic does not match its spec (see SPEC-CONFORMANCE-AUDIT-PLAN.md)

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions