Repository: python/mypy

Issue:
Built-in generics as super classes
**Bug Report**

Please consider the following stub file:

```python
class Foo(list[str]):
    bar: list[str]
```

When checking this with `mypy --python-version=3.8 foo.pyi` (mypy 0.910, Python 3.9.4), I get the following output:

```
foo.pyi:1: error: "list" is not subscriptable
Found 1 error in 1 file (checked 1 source file)
```

Please note that it complains about line 1, but not line 2. It will not complain when running in Python 3.9+ mode. See also #9980 and #10303.



Discussion:

Patch:
diff --git a/mypy/semanal.py b/mypy/semanal.py
--- a/mypy/semanal.py
+++ b/mypy/semanal.py
@@ -76,7 +76,7 @@
     get_nongen_builtins, get_member_expr_fullname, REVEAL_TYPE,
     REVEAL_LOCALS, is_final_node, TypedDictExpr, type_aliases_source_versions,
     EnumCallExpr, RUNTIME_PROTOCOL_DECOS, FakeExpression, Statement, AssignmentExpr,
-    ParamSpecExpr
+    ParamSpecExpr, EllipsisExpr
 )
 from mypy.tvar_scope import TypeVarLikeScope
 from mypy.typevars import fill_typevars
@@ -91,7 +91,8 @@
     FunctionLike, UnboundType, TypeVarDef, TupleType, UnionType, StarType,
     CallableType, Overloaded, Instance, Type, AnyType, LiteralType, LiteralValue,
     TypeTranslator, TypeOfAny, TypeType, NoneType, PlaceholderType, TPDICT_NAMES, ProperType,
-    get_proper_type, get_proper_types, TypeAliasType)
+    get_proper_type, get_proper_types, TypeAliasType
+)
 from mypy.typeops import function_type
 from mypy.type_visitor import TypeQuery
 from mypy.nodes import implicit_module_attrs
@@ -3867,7 +3868,8 @@ def analyze_type_application(self, expr: IndexExpr) -> None:
         # ...or directly.
         else:
             n = self.lookup_type_node(base)
-            if n and n.fullname in get_nongen_builtins(self.options.python_version):
+            if (n and n.fullname in get_nongen_builtins(self.options.python_version) and
+                    not self.is_stub_file):
                 self.fail(no_subscript_builtin_alias(n.fullname, propose_alt=False), expr)
 
     def analyze_type_application_args(self, expr: IndexExpr) -> Optional[List[Type]]:
@@ -3883,6 +3885,9 @@ def analyze_type_application_args(self, expr: IndexExpr) -> Optional[List[Type]]
         types: List[Type] = []
         if isinstance(index, TupleExpr):
             items = index.items
+            is_tuple = isinstance(expr.base, RefExpr) and expr.base.fullname == 'builtins.tuple'
+            if is_tuple and len(items) == 2 and isinstance(items[-1], EllipsisExpr):
+                items = items[:-1]
         else:
             items = [index]
         for item in items:
diff --git a/mypy/typeanal.py b/mypy/typeanal.py
--- a/mypy/typeanal.py
+++ b/mypy/typeanal.py
@@ -281,7 +281,8 @@ def try_analyze_special_unbound_type(self, t: UnboundType, fullname: str) -> Opt
             return AnyType(TypeOfAny.from_error)
         elif (fullname == 'typing.Tuple' or
              (fullname == 'builtins.tuple' and (self.options.python_version >= (3, 9) or
-                                                self.api.is_future_flag_set('annotations')))):
+                                                self.api.is_future_flag_set('annotations') or
+                                                self.allow_unnormalized))):
             # Tuple is special because it is involved in builtin import cycle
             # and may be not ready when used.
             sym = self.api.lookup_fully_qualified_or_none('builtins.tuple')


Test patch:
diff --git a/test-data/unit/check-generic-alias.test b/test-data/unit/check-generic-alias.test
--- a/test-data/unit/check-generic-alias.test
+++ b/test-data/unit/check-generic-alias.test
@@ -239,3 +239,46 @@ t09: tuple[int, ...] = (1, 2, 3)
 from typing import Tuple
 t10: Tuple[int, ...] = t09
 [builtins fixtures/tuple.pyi]
+
+[case testTypeAliasWithBuiltinTuple]
+# flags: --python-version 3.9
+
+A = tuple[int, ...]
+a: A = ()
+b: A = (1, 2, 3)
+c: A = ('x', 'y')  # E: Incompatible types in assignment (expression has type "Tuple[str, str]", variable has type "Tuple[int, ...]")
+
+B = tuple[int, str]
+x: B = (1, 'x')
+y: B = ('x', 1)  # E: Incompatible types in assignment (expression has type "Tuple[str, int]", variable has type "Tuple[int, str]")
+
+reveal_type(tuple[int, ...]())  # N: Revealed type is "builtins.tuple[builtins.int*]"
+[builtins fixtures/tuple.pyi]
+
+[case testTypeAliasWithBuiltinTupleInStub]
+# flags: --python-version 3.6
+import m
+reveal_type(m.a)  # N: Revealed type is "builtins.tuple[builtins.int]"
+reveal_type(m.b)  # N: Revealed type is "Tuple[builtins.int, builtins.str]"
+
+[file m.pyi]
+A = tuple[int, ...]
+a: A
+B = tuple[int, str]
+b: B
+[builtins fixtures/tuple.pyi]
+
+[case testTypeAliasWithBuiltinListInStub]
+# flags: --python-version 3.6
+import m
+reveal_type(m.a)  # N: Revealed type is "builtins.list[builtins.int]"
+reveal_type(m.b)  # N: Revealed type is "builtins.list[builtins.list[builtins.int]]"
+
+[file m.pyi]
+A = list[int]
+a: A
+B = list[list[int]]
+b: B
+class C(list[int]):
+    pass
+[builtins fixtures/list.pyi]