diff --git a/docs/source/config_file.rst b/docs/source/config_file.rst index 9e79ff99937b..b5ce1b0c1171 100644 --- a/docs/source/config_file.rst +++ b/docs/source/config_file.rst @@ -366,7 +366,7 @@ section of the command line docs. .. confval:: no_site_packages - :type: boolean + :type: bool :default: False Disables using type information in installed packages (see :pep:`561`). diff --git a/mypy/message_registry.py b/mypy/message_registry.py index 776d0bfef213..f7412ec6ec8f 100644 --- a/mypy/message_registry.py +++ b/mypy/message_registry.py @@ -29,6 +29,12 @@ def with_additional_msg(self, info: str) -> ErrorMessage: INVALID_TYPE_RAW_ENUM_VALUE: Final = ErrorMessage( "Invalid type: try using Literal[{}.{}] instead?", codes.VALID_TYPE ) +INVALID_TYPE_FROZENSET_LITERAL: Final = ErrorMessage( + "Invalid type for item of frozenset literal: {})" +) +INVALID_TYPE_TUPLE_LITERAL: Final = ErrorMessage("Invalid type for item of tuple literal: {}}") +FLOAT_NOT_EXPECTED: Final = ErrorMessage("Float not expected") +FLOAT_EXPECTED: Final = ErrorMessage("Float expected (actual type is {})") # Type checker error message constants NO_RETURN_VALUE_EXPECTED: Final = ErrorMessage("No return value expected", codes.RETURN_VALUE) @@ -162,6 +168,13 @@ def with_additional_msg(self, info: str) -> ErrorMessage: ) NOT_CALLABLE: Final = "{} not callable" TYPE_MUST_BE_USED: Final = "Value of type {} must be used" +TYPES_NOT_COMPATIBLE: Final = ErrorMessage("{} and {} are not compatible") +CANNOT_COERSE_SRC_DEST: Final = ErrorMessage("Cannot coerce source type {} to dest type {}") +INVALID_CONTROL_OPERATION_TARGET: Final = ErrorMessage("Invalid control operation target: {}") +INCORRECT_NUMBER_ARGS: Final = ErrorMessage("Incorrect number of args for method call.") +INVALID_LITERAL_VALUE_TYPE: Final = ErrorMessage( + "Invalid literal value for type: value has type {}, but op has type {}" +) # Generic GENERIC_INSTANCE_VAR_CLASS_ACCESS: Final = ( @@ -316,3 +329,25 @@ def with_additional_msg(self, info: str) -> ErrorMessage: ARG_NAME_EXPECTED_STRING_LITERAL: Final = ErrorMessage( "Expected string literal for argument name, got {}", codes.SYNTAX ) +# Semanal newtype +NEWTYPE_PROTOCOL_CLASSES: Final = ErrorMessage("NewType cannot be used with protocol classes") +ARG_1_NEWTYPE_LITERAL: Final = ErrorMessage("Argument 1 to NewType(...) must be a string literal") +ARG_2_NEWTYPE_SUBCLASSABLE: Final = ErrorMessage( + "Argument 2 to NewType(...) must be subclassable (got {})" +) +ARG_2_NEWTYPE_INVALID_TYPE: Final = ErrorMessage("Argument 2 to NewType(...) must be a valid type") +CANNOT_DECLARE_TYPE: Final = ErrorMessage("Cannot declare the type of a NewType declaration") +CANNOT_REDEFINE_NEWTYPE: Final = ErrorMessage("Cannot redefine {} as a NewType") +EXCEPT_TWO_POSITIONAL_ARGS: Final = ErrorMessage( + "NewType(...) expects exactly two positional arguments" +) +MATCH_ERROR_STR_ARG1_VAR_NAME: Final = ErrorMessage( + "String argument 1 {} to NewType(...) does not match variable name {}" +) +# Blocks +BLOCK_NOT_TERMINATED: Final = ErrorMessage("Block not terminated") +OPERATIONS_AFTER_CONTROL: Final = ErrorMessage("Block has operations after control op") +# Op +FUNC_DUPLICATE_OP: Final = ErrorMessage("Func has a duplicate op") +INVALID_OP_REFERENCE_TYPE: Final = ErrorMessage("Invalid op reference to op of type {}") +INVALID_OP_REFERENCE_REGISTER: Final = ErrorMessage("Invalid op reference to register {}") diff --git a/mypy/semanal.py b/mypy/semanal.py index 3ca758ad4eb1..8934dc9321b7 100644 --- a/mypy/semanal.py +++ b/mypy/semanal.py @@ -2189,10 +2189,6 @@ def configure_base_classes( if not self.verify_base_classes(defn): self.set_dummy_mro(defn.info) return - if not self.verify_duplicate_base_classes(defn): - # We don't want to block the typechecking process, - # so, we just insert `Any` as the base class and show an error. - self.set_any_mro(defn.info) self.calculate_class_mro(defn, self.object_type) def configure_tuple_base_class(self, defn: ClassDef, base: TupleType) -> Instance: @@ -2222,11 +2218,6 @@ def set_dummy_mro(self, info: TypeInfo) -> None: info.mro = [info, self.object_type().type] info.bad_mro = True - def set_any_mro(self, info: TypeInfo) -> None: - # Give it an MRO consisting direct `Any` subclass. - info.fallback_to_any = True - info.mro = [info, self.object_type().type] - def calculate_class_mro( self, defn: ClassDef, obj_type: Callable[[], Instance] | None = None ) -> None: @@ -2307,13 +2298,11 @@ def verify_base_classes(self, defn: ClassDef) -> bool: if self.is_base_class(info, baseinfo): self.fail("Cycle in inheritance hierarchy", defn) cycle = True - return not cycle - - def verify_duplicate_base_classes(self, defn: ClassDef) -> bool: - dup = find_duplicate(defn.info.direct_base_classes()) + dup = find_duplicate(info.direct_base_classes()) if dup: - self.fail(f'Duplicate base class "{dup.name}"', defn) - return not dup + self.fail(f'Duplicate base class "{dup.name}"', defn, blocker=True) + return False + return not cycle def is_base_class(self, t: TypeInfo, s: TypeInfo) -> bool: """Determine if t is a base class of s (but do not use mro).""" diff --git a/mypyc/analysis/ircheck.py b/mypyc/analysis/ircheck.py index 2e6b7320e898..fd7ea743146f 100644 --- a/mypyc/analysis/ircheck.py +++ b/mypyc/analysis/ircheck.py @@ -1,6 +1,8 @@ """Utilities for checking that internal ir is valid and consistent.""" from __future__ import annotations +from mypy import message_registry +from mypy.message_registry import ErrorMessage from mypyc.ir.func_ir import FUNC_STATICMETHOD, FuncIR from mypyc.ir.ops import ( Assign, @@ -69,7 +71,7 @@ class FnError: - def __init__(self, source: Op | BasicBlock, desc: str) -> None: + def __init__(self, source: Op | BasicBlock, desc: ErrorMessage) -> None: self.source = source self.desc = desc @@ -91,14 +93,17 @@ def check_func_ir(fn: FuncIR) -> list[FnError]: for block in fn.blocks: if not block.terminated: errors.append( - FnError(source=block.ops[-1] if block.ops else block, desc="Block not terminated") + FnError( + source=block.ops[-1] if block.ops else block, + desc=message_registry.BLOCK_NOT_TERMINATED, + ) ) for op in block.ops[:-1]: if isinstance(op, ControlOp): - errors.append(FnError(source=op, desc="Block has operations after control op")) + errors.append(FnError(source=op, desc=message_registry.OPERATIONS_AFTER_CONTROL)) if op in op_set: - errors.append(FnError(source=op, desc="Func has a duplicate op")) + errors.append(FnError(source=op, desc=message_registry.FUNC_DUPLICATE_OP)) op_set.add(op) errors.extend(check_op_sources_valid(fn)) @@ -122,7 +127,7 @@ def assert_func_ir_valid(fn: FuncIR) -> None: if errors: raise IrCheckException( "Internal error: Generated invalid IR: \n" - + "\n".join(format_func(fn, [(e.source, e.desc) for e in errors])) + + "\n".join(format_func(fn, [(e.source, e.desc.value) for e in errors])) ) @@ -152,14 +157,19 @@ def check_op_sources_valid(fn: FuncIR) -> list[FnError]: errors.append( FnError( source=op, - desc=f"Invalid op reference to op of type {type(source).__name__}", + desc=message_registry.INVALID_OP_REFERENCE_TYPE.format( + type(source).__name__ + ), ) ) elif isinstance(source, Register): if source not in valid_registers: errors.append( FnError( - source=op, desc=f"Invalid op reference to register {source.name!r}" + source=op, + desc=message_registry.INVALID_OP_REFERENCE_REGISTER.format( + source.name + ), ) ) @@ -208,31 +218,31 @@ def __init__(self, parent_fn: FuncIR) -> None: self.parent_fn = parent_fn self.errors: list[FnError] = [] - def fail(self, source: Op, desc: str) -> None: + def fail(self, source: Op, desc: ErrorMessage) -> None: self.errors.append(FnError(source=source, desc=desc)) def check_control_op_targets(self, op: ControlOp) -> None: for target in op.targets(): if target not in self.parent_fn.blocks: - self.fail(source=op, desc=f"Invalid control operation target: {target.label}") + self.fail( + op, message_registry.INVALID_CONTROL_OPERATION_TARGET.format(target.label) + ) def check_type_coercion(self, op: Op, src: RType, dest: RType) -> None: if not can_coerce_to(src, dest): - self.fail( - source=op, desc=f"Cannot coerce source type {src.name} to dest type {dest.name}" - ) + self.fail(op, message_registry.CANNOT_COERSE_SRC_DEST.format(src.name, dest.name)) def check_compatibility(self, op: Op, t: RType, s: RType) -> None: if not can_coerce_to(t, s) or not can_coerce_to(s, t): - self.fail(source=op, desc=f"{t.name} and {s.name} are not compatible") + self.fail(op, message_registry.TYPES_NOT_COMPATIBLE.format(t.name, s.name)) def expect_float(self, op: Op, v: Value) -> None: if not is_float_rprimitive(v.type): - self.fail(op, f"Float expected (actual type is {v.type})") + self.fail(op, message_registry.FLOAT_EXPECTED.format(v.type)) def expect_non_float(self, op: Op, v: Value) -> None: if is_float_rprimitive(v.type): - self.fail(op, "Float not expected") + self.fail(op, message_registry.FLOAT_NOT_EXPECTED) def visit_goto(self, op: Goto) -> None: self.check_control_op_targets(op) @@ -265,7 +275,7 @@ def visit_load_error_value(self, op: LoadErrorValue) -> None: def check_tuple_items_valid_literals(self, op: LoadLiteral, t: tuple[object, ...]) -> None: for x in t: if x is not None and not isinstance(x, (str, bytes, bool, int, float, complex, tuple)): - self.fail(op, f"Invalid type for item of tuple literal: {type(x)})") + self.fail(op, message_registry.INVALID_TYPE_TUPLE_LITERAL.format(type(x))) if isinstance(x, tuple): self.check_tuple_items_valid_literals(op, x) @@ -276,7 +286,7 @@ def check_frozenset_items_valid_literals(self, op: LoadLiteral, s: frozenset[obj elif isinstance(x, tuple): self.check_tuple_items_valid_literals(op, x) else: - self.fail(op, f"Invalid type for item of frozenset literal: {type(x)})") + self.fail(op, message_registry.INVALID_TYPE_FROZENSET_LITERAL.format(type(x))) def visit_load_literal(self, op: LoadLiteral) -> None: expected_type = None @@ -307,9 +317,7 @@ def visit_load_literal(self, op: LoadLiteral) -> None: if op.type.name not in [expected_type, "builtins.object"]: self.fail( - op, - f"Invalid literal value for type: value has " - f"type {expected_type}, but op has type {op.type.name}", + op, message_registry.INVALID_LITERAL_VALUE_TYPE.format(expected_type, op.type.name) ) def visit_get_attr(self, op: GetAttr) -> None: @@ -358,7 +366,7 @@ def visit_method_call(self, op: MethodCall) -> None: decl_index = 1 if len(op.args) + decl_index != len(method_decl.sig.args): - self.fail(op, "Incorrect number of args for method call.") + self.fail(op, message_registry.INCORRECT_NUMBER_ARGS) # Skip the receiver argument (self) for arg_value, arg_runtime in zip(op.args, method_decl.sig.args[decl_index:]): diff --git a/mypyc/codegen/emitfunc.py b/mypyc/codegen/emitfunc.py index 7e6d775d74b4..bcd5fac45f94 100644 --- a/mypyc/codegen/emitfunc.py +++ b/mypyc/codegen/emitfunc.py @@ -775,8 +775,6 @@ def reg(self, reg: Value) -> str: return "INFINITY" elif r == "-inf": return "-INFINITY" - elif r == "nan": - return "NAN" return r else: return self.emitter.reg(reg) diff --git a/mypyc/codegen/literals.py b/mypyc/codegen/literals.py index 8f84089221c3..d8fd115be99e 100644 --- a/mypyc/codegen/literals.py +++ b/mypyc/codegen/literals.py @@ -265,8 +265,6 @@ def float_to_c(x: float) -> str: return "INFINITY" elif s == "-inf": return "-INFINITY" - elif s == "nan": - return "NAN" return s diff --git a/mypyc/irbuild/builder.py b/mypyc/irbuild/builder.py index 26aa17071974..f071cc20f6b6 100644 --- a/mypyc/irbuild/builder.py +++ b/mypyc/irbuild/builder.py @@ -48,7 +48,6 @@ ) from mypy.types import ( AnyType, - DeletedType, Instance, ProperType, TupleType, @@ -302,9 +301,6 @@ def load_bytes_from_str_literal(self, value: str) -> Value: def load_int(self, value: int) -> Value: return self.builder.load_int(value) - def load_float(self, value: float) -> Value: - return self.builder.load_float(value) - def unary_op(self, lreg: Value, expr_op: str, line: int) -> Value: return self.builder.unary_op(lreg, expr_op, line) @@ -574,10 +570,6 @@ def get_assignment_target( self.error("Cannot assign to the first argument of classmethod", line) if lvalue.kind == LDEF: if symbol not in self.symtables[-1]: - if isinstance(symbol, Var) and not isinstance(symbol.type, DeletedType): - reg_type = self.type_to_rtype(symbol.type) - else: - reg_type = self.node_type(lvalue) # If the function is a generator function, then first define a new variable # in the current function's environment class. Next, define a target that # refers to the newly defined variable in that environment class. Add the @@ -585,11 +577,14 @@ def get_assignment_target( # current environment. if self.fn_info.is_generator: return self.add_var_to_env_class( - symbol, reg_type, self.fn_info.generator_class, reassign=False + symbol, + self.node_type(lvalue), + self.fn_info.generator_class, + reassign=False, ) # Otherwise define a new local variable. - return self.add_local_reg(symbol, reg_type) + return self.add_local_reg(symbol, self.node_type(lvalue)) else: # Assign to a previously defined variable. return self.lookup(symbol) diff --git a/mypyc/irbuild/expression.py b/mypyc/irbuild/expression.py index 4ebc422ed535..30537777fcc1 100644 --- a/mypyc/irbuild/expression.py +++ b/mypyc/irbuild/expression.py @@ -6,7 +6,6 @@ from __future__ import annotations -import math from typing import Callable, Sequence from mypy.nodes import ( @@ -129,10 +128,6 @@ def transform_name_expr(builder: IRBuilder, expr: NameExpr) -> Value: if fullname == "builtins.False": return builder.false() - math_literal = transform_math_literal(builder, fullname) - if math_literal is not None: - return math_literal - if isinstance(expr.node, Var) and expr.node.is_final: value = builder.emit_load_final( expr.node, @@ -197,10 +192,6 @@ def transform_member_expr(builder: IRBuilder, expr: MemberExpr) -> Value: if value is not None: return value - math_literal = transform_math_literal(builder, expr.fullname) - if math_literal is not None: - return math_literal - if isinstance(expr.node, MypyFile) and expr.node.fullname in builder.imports: return builder.load_module(expr.node.fullname) @@ -1052,18 +1043,3 @@ def transform_assignment_expr(builder: IRBuilder, o: AssignmentExpr) -> Value: target = builder.get_assignment_target(o.target) builder.assign(target, value, o.line) return value - - -def transform_math_literal(builder: IRBuilder, fullname: str) -> Value | None: - if fullname == "math.e": - return builder.load_float(math.e) - if fullname == "math.pi": - return builder.load_float(math.pi) - if fullname == "math.inf": - return builder.load_float(math.inf) - if fullname == "math.nan": - return builder.load_float(math.nan) - if fullname == "math.tau": - return builder.load_float(math.tau) - - return None diff --git a/mypyc/test-data/irbuild-math.test b/mypyc/test-data/irbuild-math.test deleted file mode 100644 index 470e60c74f7d..000000000000 --- a/mypyc/test-data/irbuild-math.test +++ /dev/null @@ -1,64 +0,0 @@ -[case testMathLiteralsAreInlined] -import math -from math import pi, e, tau, inf, nan - -def f1() -> float: - return pi - -def f2() -> float: - return math.pi - -def f3() -> float: - return math.e - -def f4() -> float: - return math.e - -def f5() -> float: - return math.tau - -def f6() -> float: - return math.tau - -def f7() -> float: - return math.inf -def f8() -> float: - return math.inf - -def f9() -> float: - return math.nan - -def f10() -> float: - return math.nan - -[out] -def f1(): -L0: - return 3.141592653589793 -def f2(): -L0: - return 3.141592653589793 -def f3(): -L0: - return 2.718281828459045 -def f4(): -L0: - return 2.718281828459045 -def f5(): -L0: - return 6.283185307179586 -def f6(): -L0: - return 6.283185307179586 -def f7(): -L0: - return inf -def f8(): -L0: - return inf -def f9(): -L0: - return nan -def f10(): -L0: - return nan diff --git a/mypyc/test-data/run-math.test b/mypyc/test-data/run-math.test index 266b4851575f..64d5c1812afa 100644 --- a/mypyc/test-data/run-math.test +++ b/mypyc/test-data/run-math.test @@ -4,7 +4,6 @@ from typing import Any, Callable from typing_extensions import Final import math -from math import pi, e, tau, inf, nan from testutil import assertRaises, float_vals, assertDomainError, assertMathRangeError pymath: Any = math @@ -87,20 +86,3 @@ def test_isinf() -> None: def test_isnan() -> None: for x in float_vals: assert repr(math.isnan(x)) == repr(pymath.isnan(x)) - - -def test_pi_is_inlined_correctly() -> None: - assert math.pi == pi == 3.141592653589793 - -def test_e_is_inlined_correctly() -> None: - assert math.e == e == 2.718281828459045 - -def test_tau_is_inlined_correctly() -> None: - assert math.tau == tau == 6.283185307179586 - -def test_inf_is_inlined_correctly() -> None: - assert math.inf == inf == float("inf") - -def test_nan_is_inlined_correctly() -> None: - assert math.isnan(math.nan) - assert math.isnan(nan) diff --git a/mypyc/test-data/run-misc.test b/mypyc/test-data/run-misc.test index fd0eb5022236..33f23ea3e943 100644 --- a/mypyc/test-data/run-misc.test +++ b/mypyc/test-data/run-misc.test @@ -84,36 +84,6 @@ assert f(a) is a assert g(None) == 1 assert g(a) == 2 -[case testInferredOptionalAssignment] -from typing import Any, Generator - -def f(b: bool) -> Any: - if b: - x = None - else: - x = 1 - - if b: - y = 1 - else: - y = None - - m = 1 if b else None - n = None if b else 1 - return ((x, y), (m, n)) - -def gen(b: bool) -> Generator[Any, None, None]: - if b: - y = 1 - else: - y = None - yield y - -assert f(False) == ((1, None), (None, 1)) -assert f(True) == ((None, 1), (1, None)) -assert next(gen(False)) is None -assert next(gen(True)) == 1 - [case testWith] from typing import Any class Thing: diff --git a/mypyc/test/test_irbuild.py b/mypyc/test/test_irbuild.py index fe347c855661..86bdf7c590d8 100644 --- a/mypyc/test/test_irbuild.py +++ b/mypyc/test/test_irbuild.py @@ -49,7 +49,6 @@ "irbuild-singledispatch.test", "irbuild-constant-fold.test", "irbuild-glue-methods.test", - "irbuild-math.test", ] if sys.version_info >= (3, 10): diff --git a/mypyc/test/test_ircheck.py b/mypyc/test/test_ircheck.py index 008963642272..1ed95a86c50d 100644 --- a/mypyc/test/test_ircheck.py +++ b/mypyc/test/test_ircheck.py @@ -2,6 +2,7 @@ import unittest +from mypy import message_registry from mypyc.analysis.ircheck import FnError, can_coerce_to, check_func_ir from mypyc.ir.class_ir import ClassIR from mypyc.ir.func_ir import FuncDecl, FuncIR, FuncSignature @@ -75,7 +76,7 @@ def test_valid_fn(self) -> None: def test_block_not_terminated_empty_block(self) -> None: block = self.basic_block([]) fn = FuncIR(decl=self.func_decl(name="func_1"), arg_regs=[], blocks=[block]) - assert_has_error(fn, FnError(source=block, desc="Block not terminated")) + assert_has_error(fn, FnError(source=block, desc=message_registry.BLOCK_NOT_TERMINATED)) def test_valid_goto(self) -> None: block_1 = self.basic_block([Return(value=NONE_VALUE)]) @@ -93,20 +94,29 @@ def test_invalid_goto(self) -> None: # block_1 omitted blocks=[block_2], ) - assert_has_error(fn, FnError(source=goto, desc="Invalid control operation target: 1")) + assert_has_error( + fn, + FnError(source=goto, desc=message_registry.INVALID_CONTROL_OPERATION_TARGET.format(1)), + ) def test_invalid_register_source(self) -> None: ret = Return(value=Register(type=none_rprimitive, name="r1")) block = self.basic_block([ret]) fn = FuncIR(decl=self.func_decl(name="func_1"), arg_regs=[], blocks=[block]) - assert_has_error(fn, FnError(source=ret, desc="Invalid op reference to register 'r1'")) + assert_has_error( + fn, + FnError(source=ret, desc=message_registry.INVALID_OP_REFERENCE_REGISTER.format("r1")), + ) def test_invalid_op_source(self) -> None: ret = Return(value=LoadLiteral(value="foo", rtype=str_rprimitive)) block = self.basic_block([ret]) fn = FuncIR(decl=self.func_decl(name="func_1"), arg_regs=[], blocks=[block]) assert_has_error( - fn, FnError(source=ret, desc="Invalid op reference to op of type LoadLiteral") + fn, + FnError( + source=ret, desc=message_registry.INVALID_OP_REFERENCE_TYPE.format("LoadLiteral") + ), ) def test_invalid_return_type(self) -> None: @@ -117,7 +127,10 @@ def test_invalid_return_type(self) -> None: blocks=[self.basic_block([ret])], ) assert_has_error( - fn, FnError(source=ret, desc="Cannot coerce source type int32 to dest type int64") + fn, + FnError( + source=ret, desc=message_registry.CANNOT_COERSE_SRC_DEST.format("int32", "int64") + ), ) def test_invalid_assign(self) -> None: @@ -130,7 +143,11 @@ def test_invalid_assign(self) -> None: blocks=[self.basic_block([assign, ret])], ) assert_has_error( - fn, FnError(source=assign, desc="Cannot coerce source type int32 to dest type int64") + fn, + FnError( + source=assign, + desc=message_registry.CANNOT_COERSE_SRC_DEST.format("int32", "int64"), + ), ) def test_can_coerce_to(self) -> None: @@ -161,7 +178,7 @@ def test_duplicate_op(self) -> None: assign = Assign(dest=arg_reg, src=Integer(value=5, rtype=int32_rprimitive)) block = self.basic_block([assign, assign, Return(value=NONE_VALUE)]) fn = FuncIR(decl=self.func_decl(name="func_1"), arg_regs=[], blocks=[block]) - assert_has_error(fn, FnError(source=assign, desc="Func has a duplicate op")) + assert_has_error(fn, FnError(source=assign, desc=message_registry.FUNC_DUPLICATE_OP)) def test_pprint(self) -> None: block_1 = self.basic_block([Return(value=NONE_VALUE)]) diff --git a/test-data/unit/check-classes.test b/test-data/unit/check-classes.test index c2eddbc597a0..3af20bd1e7ea 100644 --- a/test-data/unit/check-classes.test +++ b/test-data/unit/check-classes.test @@ -4124,31 +4124,12 @@ int.__eq__(3, 4) main:33: error: Too few arguments for "__eq__" of "int" main:33: error: Unsupported operand types for == ("int" and "Type[int]") -[case testDupBaseClasses] -class A: - def method(self) -> str: ... - -class B(A, A): # E: Duplicate base class "A" - attr: int - -b: B - -reveal_type(b.method()) # N: Revealed type is "Any" -reveal_type(b.missing()) # N: Revealed type is "Any" -reveal_type(b.attr) # N: Revealed type is "builtins.int" - -[case testDupBaseClassesGeneric] -from typing import Generic, TypeVar - -T = TypeVar('T') -class A(Generic[T]): - def method(self) -> T: ... - -class B(A[int], A[str]): # E: Duplicate base class "A" - attr: int - -reveal_type(B().method()) # N: Revealed type is "Any" -reveal_type(B().attr) # N: Revealed type is "builtins.int" +[case testMroSetAfterError] +class C(str, str): + foo = 0 + bar = foo +[out] +main:1: error: Duplicate base class "str" [case testCannotDetermineMro] class A: pass diff --git a/test-data/unit/lib-stub/math.pyi b/test-data/unit/lib-stub/math.pyi index 06f8878a563e..587b04a56de8 100644 --- a/test-data/unit/lib-stub/math.pyi +++ b/test-data/unit/lib-stub/math.pyi @@ -1,8 +1,4 @@ pi: float -e: float -tau: float -inf: float -nan: float def sqrt(__x: float) -> float: ... def sin(__x: float) -> float: ... def cos(__x: float) -> float: ...