diff --git a/mypy/applytype.py b/mypy/applytype.py index 997d7ffd3d4dc..6d2f3a9a1de0a 100644 --- a/mypy/applytype.py +++ b/mypy/applytype.py @@ -42,7 +42,7 @@ def apply_generic_arguments(callable: CallableType, types: List[Type], upper_bound = callable.variables[i].upper_bound if (type and not isinstance(type, PartialType) and - not mypy.subtypes.satisfies_upper_bound(type, upper_bound)): + not mypy.subtypes.is_subtype(type, upper_bound)): msg.incompatible_typevar_value(callable, i + 1, type, context) # Create a map from type variable id to target type. diff --git a/mypy/checker.py b/mypy/checker.py index 09c58c2b2dc89..1f45c79e85472 100644 --- a/mypy/checker.py +++ b/mypy/checker.py @@ -25,7 +25,7 @@ ) from mypy import nodes from mypy.types import ( - Type, AnyType, CallableType, Void, FunctionLike, Overloaded, TupleType, TypedDictType, + Type, AnyType, CallableType, FunctionLike, Overloaded, TupleType, TypedDictType, Instance, NoneTyp, ErrorType, strip_type, TypeType, UnionType, TypeVarId, TypeVarType, PartialType, DeletedType, UninhabitedType, TypeVarDef, true_only, false_only, function_type, is_named_instance @@ -300,7 +300,7 @@ def check_overlapping_overloads(self, defn: OverloadedFuncDef) -> None: # # A classic generator must define a return type that's either # `Generator[ty, tc, tr]`, Iterator[ty], or Iterable[ty] (or - # object or Any). If tc/tr are not given, both are Void. + # object or Any). If tc/tr are not given, both are None. # # A coroutine must define a return type corresponding to tr; the # other two are unconstrained. The "external" return type (seen @@ -377,11 +377,6 @@ def get_generator_yield_type(self, return_type: Type, is_coroutine: bool) -> Typ # AwaitableGenerator, Generator, AsyncGenerator, Iterator, or Iterable; ty is args[0]. ret_type = return_type.args[0] # TODO not best fix, better have dedicated yield token - if isinstance(ret_type, NoneTyp): - if experiments.STRICT_OPTIONAL: - return NoneTyp(is_ret_type=True) - else: - return Void() return ret_type else: # If the function's declared supertype of Generator has no type @@ -414,10 +409,7 @@ def get_generator_receive_type(self, return_type: Type, is_coroutine: bool) -> T else: # `return_type` is a supertype of Generator, so callers won't be able to send it # values. IOW, tc is None. - if experiments.STRICT_OPTIONAL: - return NoneTyp(is_ret_type=True) - else: - return Void() + return NoneTyp() def get_generator_return_type(self, return_type: Type, is_coroutine: bool) -> Type: """Given the declared return type of a generator (t), return the type it returns (tr).""" @@ -529,7 +521,7 @@ def check_func_def(self, defn: FuncItem, typ: CallableType, name: str) -> None: if fdef: # Check if __init__ has an invalid, non-None return type. if (fdef.info and fdef.name() in ('__init__', '__init_subclass__') and - not isinstance(typ.ret_type, (Void, NoneTyp)) and + not isinstance(typ.ret_type, NoneTyp) and not self.dynamic_funcs[-1]): self.fail(messages.MUST_HAVE_NONE_RETURN_TYPE.format(fdef.name()), item.type) @@ -572,7 +564,7 @@ def is_implicit_any(t: Type) -> bool: if (self.options.python_version[0] == 2 and isinstance(typ.ret_type, Instance) and typ.ret_type.type.fullname() == 'typing.Generator'): - if not isinstance(typ.ret_type.args[2], (Void, NoneTyp, AnyType)): + if not isinstance(typ.ret_type.args[2], (NoneTyp, AnyType)): self.fail(messages.INVALID_GENERATOR_RETURN_ITEM_TYPE, typ) # Fix the type if decorated with `@types.coroutine` or `@asyncio.coroutine`. @@ -660,7 +652,7 @@ def is_implicit_any(t: Type) -> bool: else: return_type = self.return_types[-1] - if (not isinstance(return_type, (Void, NoneTyp, AnyType)) + if (not isinstance(return_type, (NoneTyp, AnyType)) and not self.is_trivial_body(defn.body)): # Control flow fell off the end of a function that was # declared to return a non-None type and is not @@ -1149,11 +1141,8 @@ def check_assignment(self, lvalue: Lvalue, rvalue: Expression, infer_lvalue_type partial_types = self.find_partial_types(var) if partial_types is not None: if not self.current_node_deferred: - if experiments.STRICT_OPTIONAL: - var.type = UnionType.make_simplified_union( - [rvalue_type, NoneTyp()]) - else: - var.type = rvalue_type + var.type = UnionType.make_simplified_union( + [rvalue_type, NoneTyp()]) else: var.type = None del partial_types[var] @@ -1554,10 +1543,7 @@ def is_definition(self, s: Lvalue) -> bool: def infer_variable_type(self, name: Var, lvalue: Lvalue, init_type: Type, context: Context) -> None: """Infer the type of initialized variables from initializer type.""" - if self.is_unusable_type(init_type): - self.check_usable_type(init_type, context) - self.set_inference_error_fallback_type(name, lvalue, init_type, context) - elif isinstance(init_type, DeletedType): + if isinstance(init_type, DeletedType): self.msg.deleted_as_rvalue(init_type, context) elif not is_valid_inferred_type(init_type): # We cannot use the type of the initialization expression for full type @@ -1748,7 +1734,7 @@ def try_infer_partial_type_from_indexed_assignment( del partial_types[var] def visit_expression_stmt(self, s: ExpressionStmt) -> None: - self.expr_checker.accept(s.expr) + self.expr_checker.accept(s.expr, allow_none_return=True) def visit_return_stmt(self, s: ReturnStmt) -> None: """Type check a return statement.""" @@ -1769,13 +1755,25 @@ def check_return_stmt(self, s: ReturnStmt) -> None: return if s.expr: + is_lambda = isinstance(self.scope.top_function(), FuncExpr) + declared_none_return = isinstance(return_type, NoneTyp) + declared_any_return = isinstance(return_type, AnyType) + + # This controls whether or not we allow a function call that + # returns None as the expression of this return statement. + # E.g. `return f()` for some `f` that returns None. We allow + # this only if we're in a lambda or in a function that returns + # `None` or `Any`. + allow_none_func_call = is_lambda or declared_none_return or declared_any_return + # Return with a value. - typ = self.expr_checker.accept(s.expr, return_type) + typ = self.expr_checker.accept(s.expr, + return_type, + allow_none_return=allow_none_func_call) if defn.is_async_generator: self.fail("'return' with value in async generator is not allowed", s) return - # Returning a value of type Any is always fine. if isinstance(typ, AnyType): # (Unless you asked to be warned in that case, and the @@ -1784,10 +1782,12 @@ def check_return_stmt(self, s: ReturnStmt) -> None: self.warn(messages.RETURN_ANY.format(return_type), s) return - if self.is_unusable_type(return_type): - # Lambdas are allowed to have a unusable returns. - # Functions returning a value of type None are allowed to have a Void return. - if isinstance(self.scope.top_function(), FuncExpr) or isinstance(typ, NoneTyp): + # Disallow return expressions in functions declared to return + # None, subject to two exceptions below. + if declared_none_return: + # Lambdas are allowed to have None returns. + # Functions returning a value of type None are allowed to have a None return. + if is_lambda or isinstance(typ, NoneTyp): return self.fail(messages.NO_RETURN_VALUE_EXPECTED, s) else: @@ -1805,7 +1805,7 @@ def check_return_stmt(self, s: ReturnStmt) -> None: isinstance(return_type, AnyType)): return - if isinstance(return_type, (Void, NoneTyp, AnyType)): + if isinstance(return_type, (NoneTyp, AnyType)): return if self.in_checked_function(): @@ -1818,7 +1818,6 @@ def visit_if_stmt(self, s: IfStmt) -> None: with self.binder.frame_context(can_skip=False, fall_through=0): for e, b in zip(s.expr, s.body): t = self.expr_checker.accept(e) - self.check_usable_type(t, e) if isinstance(t, DeletedType): self.msg.deleted_as_rvalue(t, s) @@ -2058,8 +2057,6 @@ def analyze_async_iterable_item_type(self, expr: Expression) -> Type: echk = self.expr_checker iterable = echk.accept(expr) - self.check_usable_type(iterable, expr) - self.check_subtype(iterable, self.named_generic_type('typing.AsyncIterable', [AnyType()]), @@ -2077,12 +2074,8 @@ def analyze_iterable_item_type(self, expr: Expression) -> Type: echk = self.expr_checker iterable = echk.accept(expr) - self.check_usable_type(iterable, expr) if isinstance(iterable, TupleType): - if experiments.STRICT_OPTIONAL: - joined = UninhabitedType() # type: Type - else: - joined = NoneTyp() + joined = UninhabitedType() # type: Type for item in iterable.items: joined = join_types(joined, item) if isinstance(joined, ErrorType): @@ -2119,7 +2112,7 @@ def visit_del_stmt(self, s: DelStmt) -> None: m.line = s.line c = CallExpr(m, [e.index], [nodes.ARG_POS], [None]) c.line = s.line - c.accept(self.expr_checker) + self.expr_checker.accept(c, allow_none_return=True) else: s.expr.accept(self.expr_checker) for elt in flatten(s.expr): @@ -2248,21 +2241,18 @@ def check_subtype(self, subtype: Type, supertype: Type, context: Context, if is_subtype(subtype, supertype): return True else: - if self.is_unusable_type(subtype): - self.msg.does_not_return_value(subtype, context) - else: - if self.should_suppress_optional_error([subtype]): - return False - extra_info = [] # type: List[str] - if subtype_label is not None or supertype_label is not None: - subtype_str, supertype_str = self.msg.format_distinctly(subtype, supertype) - if subtype_label is not None: - extra_info.append(subtype_label + ' ' + subtype_str) - if supertype_label is not None: - extra_info.append(supertype_label + ' ' + supertype_str) - if extra_info: - msg += ' (' + ', '.join(extra_info) + ')' - self.fail(msg, context) + if self.should_suppress_optional_error([subtype]): + return False + extra_info = [] # type: List[str] + if subtype_label is not None or supertype_label is not None: + subtype_str, supertype_str = self.msg.format_distinctly(subtype, supertype) + if subtype_label is not None: + extra_info.append(subtype_label + ' ' + subtype_str) + if supertype_label is not None: + extra_info.append(supertype_label + ' ' + supertype_str) + if extra_info: + msg += ' (' + ', '.join(extra_info) + ')' + self.fail(msg, context) return False def contains_none(self, t: Type) -> bool: @@ -2369,8 +2359,7 @@ def enter_partial_types(self) -> Iterator[None]: partial_types = self.partial_types.pop() if not self.current_node_deferred: for var, context in partial_types.items(): - if (experiments.STRICT_OPTIONAL and - isinstance(var.type, PartialType) and var.type.type is None): + if isinstance(var.type, PartialType) and var.type.type is None: # None partial type: assume variable is intended to have type None var.type = NoneTyp() else: @@ -2383,18 +2372,6 @@ def find_partial_types(self, var: Var) -> Optional[Dict[Var, Context]]: return partial_types return None - def is_unusable_type(self, typ: Type) -> bool: - """Is this type an unusable type? - - The two unusable types are Void and NoneTyp(is_ret_type=True). - """ - return isinstance(typ, Void) or (isinstance(typ, NoneTyp) and typ.is_ret_type) - - def check_usable_type(self, typ: Type, context: Context) -> None: - """Generate an error if the type is not a usable type.""" - if self.is_unusable_type(typ): - self.msg.does_not_return_value(typ, context) - def temp_node(self, t: Type, context: Context = None) -> TempNode: """Create a temporary node with the given, fixed type.""" temp = TempNode(t) @@ -2925,9 +2902,6 @@ def is_valid_inferred_type_component(typ: Type) -> bool: In strict Optional mode this excludes bare None types, as otherwise every type containing None would be invalid. """ - if not experiments.STRICT_OPTIONAL: - if is_same_type(typ, NoneTyp()): - return False if is_same_type(typ, UninhabitedType()): return False elif isinstance(typ, Instance): diff --git a/mypy/checkexpr.py b/mypy/checkexpr.py index 1abb6d0992410..877b53769e7d5 100644 --- a/mypy/checkexpr.py +++ b/mypy/checkexpr.py @@ -5,7 +5,7 @@ from mypy.errors import report_internal_error from mypy.types import ( - Type, AnyType, CallableType, Overloaded, NoneTyp, Void, TypeVarDef, + Type, AnyType, CallableType, Overloaded, NoneTyp, TypeVarDef, TupleType, TypedDictType, Instance, TypeVarType, ErasedType, UnionType, PartialType, DeletedType, UnboundType, UninhabitedType, TypeType, true_only, false_only, is_named_instance, function_type, callable_type, FunctionLike, @@ -173,7 +173,7 @@ def analyze_var_ref(self, var: Var, context: Context) -> Type: else: return val - def visit_call_expr(self, e: CallExpr) -> Type: + def visit_call_expr(self, e: CallExpr, allow_none_return: bool = False) -> Type: """Type check a call expression.""" if e.analyzed: # It's really a special form that only looks like a call. @@ -192,6 +192,9 @@ def visit_call_expr(self, e: CallExpr) -> Type: ret_type = self.check_call_expr_with_callee_type(callee_type, e) if isinstance(ret_type, UninhabitedType): self.chk.binder.unreachable() + if not allow_none_return and isinstance(ret_type, NoneTyp): + self.chk.msg.does_not_return_value(callee_type, e) + return AnyType(implicit=True) return ret_type def check_typeddict_call(self, callee: TypedDictType, @@ -557,9 +560,6 @@ def infer_function_type_arguments_using_context( for arg in args: if isinstance(arg, UninhabitedType) or has_erased_component(arg): new_args.append(None) - elif not experiments.STRICT_OPTIONAL and isinstance(arg, NoneTyp): - # Don't substitute None types in non-strict-Optional mode. - new_args.append(None) else: new_args.append(arg) return self.apply_generic_arguments(callable, new_args, error_context) @@ -836,9 +836,7 @@ def check_arg(self, caller_type: Type, original_caller_type: Type, callee_type: Type, n: int, m: int, callee: CallableType, context: Context, messages: MessageBuilder) -> None: """Check the type of a single argument in a call.""" - if self.chk.is_unusable_type(caller_type): - messages.does_not_return_value(caller_type, context) - elif isinstance(caller_type, DeletedType): + if isinstance(caller_type, DeletedType): messages.deleted_as_rvalue(caller_type, context) elif not is_subtype(caller_type, callee_type): if self.chk.should_suppress_optional_error([caller_type, callee_type]): @@ -1192,8 +1190,6 @@ def visit_comparison_expr(self, e: ComparisonExpr) -> Type: if result is None: result = sub_result else: - # TODO: check on void needed? - self.check_usable_type(sub_result, e) result = join.join_types(result, sub_result) return result @@ -1344,9 +1340,6 @@ def check_boolean_op(self, e: OpExpr, context: Context) -> Type: right_type = self.analyze_cond_branch(right_map, e.right, left_type) - self.check_usable_type(left_type, context) - self.check_usable_type(right_type, context) - if right_map is None: # The boolean expression is statically known to be the left value assert left_map is not None # find_isinstance_check guarantees this @@ -1386,7 +1379,6 @@ def visit_unary_expr(self, e: UnaryExpr) -> Type: operand_type = self.accept(e.expr) op = e.op if op == 'not': - self.check_usable_type(operand_type, e) result = self.bool_type() # type: Type elif op == '-': method_type = self.analyze_external_member_access('__neg__', @@ -1520,20 +1512,12 @@ def visit_enum_index_expr(self, enum_type: TypeInfo, index: Expression, def visit_cast_expr(self, expr: CastExpr) -> Type: """Type check a cast expression.""" - source_type = self.accept(expr.expr, type_context=AnyType()) + source_type = self.accept(expr.expr, type_context=AnyType(), allow_none_return=True) target_type = expr.type if self.chk.options.warn_redundant_casts and is_same_type(source_type, target_type): self.msg.redundant_cast(target_type, expr) - if not self.is_valid_cast(source_type, target_type): - self.msg.invalid_cast(target_type, source_type, expr) return target_type - def is_valid_cast(self, source_type: Type, target_type: Type) -> bool: - """Is a cast from source_type to target_type meaningful?""" - return (isinstance(target_type, AnyType) or - (not isinstance(source_type, Void) and - not isinstance(target_type, Void))) - def visit_reveal_type_expr(self, expr: RevealTypeExpr) -> Type: """Type check a reveal_type expression.""" revealed_type = self.accept(expr.expr, type_context=self.type_context[-1]) @@ -1688,7 +1672,6 @@ def visit_tuple_expr(self, e: TupleExpr) -> Type: # context? Counterargument: Why would anyone write # (1, *(2, 3)) instead of (1, 2, 3) except in a test? tt = self.accept(item.expr) - self.check_usable_type(tt, e) if isinstance(tt, TupleType): items.extend(tt.items) j += len(tt.items) @@ -1702,7 +1685,6 @@ def visit_tuple_expr(self, e: TupleExpr) -> Type: else: tt = self.accept(item, type_context_items[j]) j += 1 - self.check_usable_type(tt, e) items.append(tt) fallback_item = join.join_type_list(items) return TupleType(items, self.chk.named_generic_type('builtins.tuple', [fallback_item])) @@ -1766,16 +1748,14 @@ def visit_func_expr(self, e: FuncExpr) -> Type: inferred_type, type_override = self.infer_lambda_type_using_context(e) if not inferred_type: # No useful type context. - ret_type = self.accept(e.expr()) - if isinstance(ret_type, NoneTyp): - ret_type = Void() + ret_type = self.accept(e.expr(), allow_none_return=True) fallback = self.named_type('builtins.function') return callable_type(e, fallback, ret_type) else: # Type context available. self.chk.check_func_item(e, type_override=type_override) if e.expr() not in self.chk.type_map: - self.accept(e.expr()) + self.accept(e.expr(), allow_none_return=True) ret_type = self.chk.type_map[e.expr()] if isinstance(ret_type, NoneTyp): # For "lambda ...: None", just use type from the context. @@ -1965,7 +1945,6 @@ def check_for_comp(self, e: Union[GeneratorExpr, DictionaryComprehension]) -> No def visit_conditional_expr(self, e: ConditionalExpr) -> Type: cond_type = self.accept(e.cond) - self.check_usable_type(cond_type, e) if self.chk.options.strict_boolean: is_bool = (isinstance(cond_type, Instance) and cond_type.type.fullname() == 'builtins.bool') @@ -2019,11 +1998,23 @@ def visit_backquote_expr(self, e: BackquoteExpr) -> Type: # Helpers # - def accept(self, node: Expression, type_context: Type = None) -> Type: - """Type check a node in the given type context.""" + def accept(self, + node: Expression, + type_context: Type = None, + allow_none_return: bool = False + ) -> Type: + """Type check a node in the given type context. If allow_none_return + is True and this expression is a call, allow it to return None. This + applies only to this expression and not any subexpressions. + """ self.type_context.append(type_context) try: - typ = node.accept(self) + if allow_none_return and isinstance(node, CallExpr): + typ = self.visit_call_expr(node, allow_none_return=True) + elif allow_none_return and isinstance(node, YieldFromExpr): + typ = self.visit_yield_from_expr(node, allow_none_return=True) + else: + typ = node.accept(self) except Exception as err: report_internal_error(err, self.chk.errors.file, node.line, self.chk.errors, self.chk.options) @@ -2035,10 +2026,6 @@ def accept(self, node: Expression, type_context: Type = None) -> Type: else: return typ - def check_usable_type(self, typ: Type, context: Context) -> None: - """Generate an error if type is Void.""" - self.chk.check_usable_type(typ, context) - def named_type(self, name: str) -> Instance: """Return an instance type with type given by the name and no type arguments. Alias for TypeChecker.named_type. @@ -2099,7 +2086,7 @@ def visit_yield_expr(self, e: YieldExpr) -> Type: return_type = self.chk.return_types[-1] expected_item_type = self.chk.get_generator_yield_type(return_type, False) if e.expr is None: - if (not isinstance(expected_item_type, (Void, NoneTyp, AnyType)) + if (not isinstance(expected_item_type, (NoneTyp, AnyType)) and self.chk.in_checked_function()): self.chk.fail(messages.YIELD_VALUE_EXPECTED, e) else: @@ -2131,7 +2118,7 @@ def check_awaitable_expr(self, t: Type, ctx: Context, msg: str) -> Type: generator = self.check_call(method, [], [], ctx)[0] return self.chk.get_generator_return_type(generator, False) - def visit_yield_from_expr(self, e: YieldFromExpr) -> Type: + def visit_yield_from_expr(self, e: YieldFromExpr, allow_none_return: bool = False) -> Type: # NOTE: Whether `yield from` accepts an `async def` decorated # with `@types.coroutine` (or `@asyncio.coroutine`) depends on # whether the generator containing the `yield from` is itself @@ -2177,17 +2164,18 @@ def visit_yield_from_expr(self, e: YieldFromExpr) -> Type: # Determine the type of the entire yield from expression. if (isinstance(iter_type, Instance) and iter_type.type.fullname() == 'typing.Generator'): - return self.chk.get_generator_return_type(iter_type, False) + expr_type = self.chk.get_generator_return_type(iter_type, False) else: # Non-Generators don't return anything from `yield from` expressions. # However special-case Any (which might be produced by an error). if isinstance(actual_item_type, AnyType): - return AnyType() + expr_type = AnyType() else: - if experiments.STRICT_OPTIONAL: - return NoneTyp(is_ret_type=True) - else: - return Void() + expr_type = NoneTyp() + + if not allow_none_return and isinstance(expr_type, NoneTyp): + self.chk.msg.does_not_return_value(None, e) + return expr_type def visit_temp_node(self, e: TempNode) -> Type: return e.type diff --git a/mypy/constraints.py b/mypy/constraints.py index bbb398348ac7d..d6e44bea857d8 100644 --- a/mypy/constraints.py +++ b/mypy/constraints.py @@ -4,7 +4,7 @@ from mypy import experiments from mypy.types import ( - CallableType, Type, TypeVisitor, UnboundType, AnyType, Void, NoneTyp, TypeVarType, + CallableType, Type, TypeVisitor, UnboundType, AnyType, NoneTyp, TypeVarType, Instance, TupleType, TypedDictType, UnionType, Overloaded, ErasedType, PartialType, DeletedType, UninhabitedType, TypeType, TypeVarId, TypeQuery, ALL_TYPES_STRATEGY, is_named_instance @@ -281,9 +281,6 @@ def visit_unbound_type(self, template: UnboundType) -> List[Constraint]: def visit_any(self, template: AnyType) -> List[Constraint]: return [] - def visit_void(self, template: Void) -> List[Constraint]: - return [] - def visit_none_type(self, template: NoneTyp) -> List[Constraint]: return [] diff --git a/mypy/erasetype.py b/mypy/erasetype.py index 47a0d7241bb2a..9a44b0456522b 100644 --- a/mypy/erasetype.py +++ b/mypy/erasetype.py @@ -1,7 +1,7 @@ from typing import Optional, Container, Callable from mypy.types import ( - Type, TypeVisitor, UnboundType, ErrorType, AnyType, Void, NoneTyp, TypeVarId, + Type, TypeVisitor, UnboundType, ErrorType, AnyType, NoneTyp, TypeVarId, Instance, TypeVarType, CallableType, TupleType, TypedDictType, UnionType, Overloaded, ErasedType, PartialType, DeletedType, TypeTranslator, TypeList, UninhabitedType, TypeType ) @@ -38,9 +38,6 @@ def visit_type_list(self, t: TypeList) -> Type: def visit_any(self, t: AnyType) -> Type: return t - def visit_void(self, t: Void) -> Type: - return t - def visit_none_type(self, t: NoneTyp) -> Type: return t @@ -66,10 +63,7 @@ def visit_type_var(self, t: TypeVarType) -> Type: def visit_callable_type(self, t: CallableType) -> Type: # We must preserve the fallback type for overload resolution to work. - if experiments.STRICT_OPTIONAL: - ret_type = NoneTyp(is_ret_type=True) # type: Type - else: - ret_type = Void() + ret_type = NoneTyp() # type: Type return CallableType([], [], [], ret_type, t.fallback) def visit_overloaded(self, t: Overloaded) -> Type: diff --git a/mypy/expandtype.py b/mypy/expandtype.py index e90a89ff607f2..41c74daf6ea39 100644 --- a/mypy/expandtype.py +++ b/mypy/expandtype.py @@ -2,7 +2,7 @@ from mypy.types import ( Type, Instance, CallableType, TypeVisitor, UnboundType, ErrorType, AnyType, - Void, NoneTyp, TypeVarType, Overloaded, TupleType, TypedDictType, UnionType, + NoneTyp, TypeVarType, Overloaded, TupleType, TypedDictType, UnionType, ErasedType, TypeList, PartialType, DeletedType, UninhabitedType, TypeType, TypeVarId, FunctionLike, TypeVarDef ) @@ -72,9 +72,6 @@ def visit_type_list(self, t: TypeList) -> Type: def visit_any(self, t: AnyType) -> Type: return t - def visit_void(self, t: Void) -> Type: - return t - def visit_none_type(self, t: NoneTyp) -> Type: return t diff --git a/mypy/fastparse.py b/mypy/fastparse.py index 935ef67b9c5f9..22d71c1b3e362 100644 --- a/mypy/fastparse.py +++ b/mypy/fastparse.py @@ -342,9 +342,6 @@ def do_func_def(self, n: Union[ast3.FunctionDef, ast3.AsyncFunctionDef], for arg, arg_type in zip(args, arg_types): self.set_type_optional(arg_type, arg.initializer) - if isinstance(return_type, UnboundType): - return_type.is_ret_type = True - func_type = None if any(arg_types) or return_type: if len(arg_types) != 1 and any(isinstance(t, EllipsisType) for t in arg_types): diff --git a/mypy/fastparse2.py b/mypy/fastparse2.py index 10965f19025bd..4ff141c426dbd 100644 --- a/mypy/fastparse2.py +++ b/mypy/fastparse2.py @@ -327,9 +327,6 @@ def visit_FunctionDef(self, n: ast27.FunctionDef) -> Statement: for arg, arg_type in zip(args, arg_types): self.set_type_optional(arg_type, arg.initializer) - if isinstance(return_type, UnboundType): - return_type.is_ret_type = True - func_type = None if any(arg_types) or return_type: if len(arg_types) != 1 and any(isinstance(t, EllipsisType) for t in arg_types): diff --git a/mypy/indirection.py b/mypy/indirection.py index b36d999fd19fb..a604899031c2b 100644 --- a/mypy/indirection.py +++ b/mypy/indirection.py @@ -51,9 +51,6 @@ def visit_error_type(self, t: types.ErrorType) -> Set[str]: def visit_any(self, t: types.AnyType) -> Set[str]: return set() - def visit_void(self, t: types.Void) -> Set[str]: - return set() - def visit_none_type(self, t: types.NoneTyp) -> Set[str]: return set() diff --git a/mypy/join.py b/mypy/join.py index d14b83ded9fb3..06d5416cd2eab 100644 --- a/mypy/join.py +++ b/mypy/join.py @@ -4,7 +4,7 @@ from typing import cast, List from mypy.types import ( - Type, AnyType, NoneTyp, Void, TypeVisitor, Instance, UnboundType, + Type, AnyType, NoneTyp, TypeVisitor, Instance, UnboundType, ErrorType, TypeVarType, CallableType, TupleType, TypedDictType, ErasedType, TypeList, UnionType, FunctionLike, Overloaded, PartialType, DeletedType, UninhabitedType, TypeType, true_or_false @@ -101,7 +101,7 @@ def __init__(self, s: Type) -> None: self.s = s def visit_unbound_type(self, t: UnboundType) -> Type: - if isinstance(self.s, Void) or isinstance(self.s, ErrorType): + if isinstance(self.s, ErrorType): return ErrorType() else: return AnyType() @@ -121,39 +121,24 @@ def visit_type_list(self, t: TypeList) -> Type: def visit_any(self, t: AnyType) -> Type: return t - def visit_void(self, t: Void) -> Type: - if isinstance(self.s, Void): - return t - else: - return ErrorType() - def visit_none_type(self, t: NoneTyp) -> Type: if experiments.STRICT_OPTIONAL: if isinstance(self.s, (NoneTyp, UninhabitedType)): return t elif isinstance(self.s, UnboundType): return AnyType() - elif isinstance(self.s, Void) or isinstance(self.s, ErrorType): + elif isinstance(self.s, ErrorType): return ErrorType() else: return UnionType.make_simplified_union([self.s, t]) else: - if not isinstance(self.s, Void): - return self.s - else: - return self.default(self.s) + return self.s def visit_uninhabited_type(self, t: UninhabitedType) -> Type: - if not isinstance(self.s, Void): - return self.s - else: - return self.default(self.s) + return self.s def visit_deleted_type(self, t: DeletedType) -> Type: - if not isinstance(self.s, Void): - return self.s - else: - return self.default(self.s) + return self.s def visit_erased_type(self, t: ErasedType) -> Type: return self.s @@ -279,7 +264,7 @@ def default(self, typ: Type) -> Type: return object_from_instance(typ) elif isinstance(typ, UnboundType): return AnyType() - elif isinstance(typ, Void) or isinstance(typ, ErrorType): + elif isinstance(typ, ErrorType): return ErrorType() elif isinstance(typ, TupleType): return self.default(typ.fallback) @@ -387,13 +372,8 @@ def object_from_instance(instance: Instance) -> Instance: def join_type_list(types: List[Type]) -> Type: if not types: # This is a little arbitrary but reasonable. Any empty tuple should be compatible - # with all variable length tuples, and this makes it possible. A better approach - # would be to use a special bottom type, which we do when strict Optional - # checking is enabled. - if experiments.STRICT_OPTIONAL: - return UninhabitedType() - else: - return NoneTyp() + # with all variable length tuples, and this makes it possible. + return UninhabitedType() joined = types[0] for t in types[1:]: joined = join_types(joined, t) diff --git a/mypy/meet.py b/mypy/meet.py index 03b8d1b58cbc5..e1e698683a762 100644 --- a/mypy/meet.py +++ b/mypy/meet.py @@ -3,7 +3,7 @@ from mypy.join import is_similar_callables, combine_similar_callables, join_type_list from mypy.types import ( - Type, AnyType, TypeVisitor, UnboundType, Void, ErrorType, NoneTyp, TypeVarType, + Type, AnyType, TypeVisitor, UnboundType, ErrorType, NoneTyp, TypeVarType, Instance, CallableType, TupleType, TypedDictType, ErasedType, TypeList, UnionType, PartialType, DeletedType, UninhabitedType, TypeType ) @@ -123,7 +123,7 @@ def __init__(self, s: Type) -> None: self.s = s def visit_unbound_type(self, t: UnboundType) -> Type: - if isinstance(self.s, Void) or isinstance(self.s, ErrorType): + if isinstance(self.s, ErrorType): return ErrorType() elif isinstance(self.s, NoneTyp): if experiments.STRICT_OPTIONAL: @@ -155,12 +155,6 @@ def visit_union_type(self, t: UnionType) -> Type: for x in t.items] return UnionType.make_simplified_union(meets) - def visit_void(self, t: Void) -> Type: - if isinstance(self.s, Void): - return t - else: - return ErrorType() - def visit_none_type(self, t: NoneTyp) -> Type: if experiments.STRICT_OPTIONAL: if isinstance(self.s, NoneTyp) or (isinstance(self.s, Instance) and @@ -169,19 +163,19 @@ def visit_none_type(self, t: NoneTyp) -> Type: else: return UninhabitedType() else: - if not isinstance(self.s, Void) and not isinstance(self.s, ErrorType): + if not isinstance(self.s, ErrorType): return t else: return ErrorType() def visit_uninhabited_type(self, t: UninhabitedType) -> Type: - if not isinstance(self.s, Void) and not isinstance(self.s, ErrorType): + if not isinstance(self.s, ErrorType): return t else: return ErrorType() def visit_deleted_type(self, t: DeletedType) -> Type: - if not isinstance(self.s, Void) and not isinstance(self.s, ErrorType): + if not isinstance(self.s, ErrorType): if isinstance(self.s, NoneTyp): if experiments.STRICT_OPTIONAL: return t @@ -293,7 +287,7 @@ def meet(self, s: Type, t: Type) -> Type: def default(self, typ: Type) -> Type: if isinstance(typ, UnboundType): return AnyType() - elif isinstance(typ, Void) or isinstance(typ, ErrorType): + elif isinstance(typ, ErrorType): return ErrorType() else: if experiments.STRICT_OPTIONAL: diff --git a/mypy/messages.py b/mypy/messages.py index 88edba48a38c5..fdbf922d4016a 100644 --- a/mypy/messages.py +++ b/mypy/messages.py @@ -11,7 +11,7 @@ from mypy.errors import Errors from mypy.types import ( Type, CallableType, Instance, TypeVarType, TupleType, TypedDictType, - UnionType, Void, NoneTyp, AnyType, Overloaded, FunctionLike, DeletedType, TypeType, + UnionType, NoneTyp, AnyType, Overloaded, FunctionLike, DeletedType, TypeType, UninhabitedType ) from mypy.nodes import ( @@ -319,8 +319,6 @@ def format_simple(self, typ: Type, verbosity: int = 0) -> str: return s else: return 'union type ({} items)'.format(len(items)) - elif isinstance(typ, Void): - return 'None' elif isinstance(typ, NoneTyp): return 'None' elif isinstance(typ, AnyType): @@ -374,8 +372,6 @@ def has_no_attr(self, typ: Type, member: str, context: Context) -> Type: if (isinstance(typ, Instance) and typ.type.has_readable_member(member)): self.fail('Member "{}" is not assignable'.format(member), context) - elif self.check_unusable_type(typ, context): - pass elif member == '__contains__': self.fail('Unsupported right operand type for in ({})'.format( self.format(typ)), context) @@ -440,9 +436,6 @@ def unsupported_operand_types(self, op: str, left_type: Any, Types can be Type objects or strings. """ - if (self.check_unusable_type(left_type, context) or - self.check_unusable_type(right_type, context)): - return left_str = '' if isinstance(left_type, str): left_str = left_type @@ -464,13 +457,12 @@ def unsupported_operand_types(self, op: str, left_type: Any, def unsupported_left_operand(self, op: str, typ: Type, context: Context) -> None: - if not self.check_unusable_type(typ, context): - if self.disable_type_names: - msg = 'Unsupported left operand type for {} (some union)'.format(op) - else: - msg = 'Unsupported left operand type for {} ({})'.format( - op, self.format(typ)) - self.fail(msg, context) + if self.disable_type_names: + msg = 'Unsupported left operand type for {} (some union)'.format(op) + else: + msg = 'Unsupported left operand type for {} ({})'.format( + op, self.format(typ)) + self.fail(msg, context) def not_callable(self, typ: Type, context: Context) -> Type: self.fail('{} not callable'.format(self.format(typ)), context) @@ -621,15 +613,11 @@ def duplicate_argument_value(self, callee: CallableType, index: int, format(capitalize(callable_name(callee)), callee.arg_names[index]), context) - def does_not_return_value(self, unusable_type: Type, context: Context) -> None: - """Report an error about use of an unusable type. - - If the type is a Void type and has a source in it, report it in the error message. - This allows giving messages such as 'Foo does not return a value'. - """ - if isinstance(unusable_type, Void) and unusable_type.source is not None: + def does_not_return_value(self, callee_type: Type, context: Context) -> None: + """Report an error about use of an unusable type.""" + if isinstance(callee_type, FunctionLike) and callee_type.get_name() is not None: self.fail('{} does not return a value'.format( - capitalize((cast(Void, unusable_type)).source)), context) + capitalize(callee_type.get_name())), context) else: self.fail('Function does not return a value', context) @@ -661,12 +649,6 @@ def no_variant_matches_arguments(self, overload: Overloaded, arg_types: List[Typ else: self.fail('No overload variant matches argument types {}'.format(arg_types), context) - def invalid_cast(self, target_type: Type, source_type: Type, - context: Context) -> None: - if not self.check_unusable_type(source_type, context): - self.fail('Cannot cast from {} to {}'.format( - self.format(source_type), self.format(target_type)), context) - def wrong_number_values_to_unpack(self, provided: int, expected: int, context: Context) -> None: if provided < expected: @@ -750,18 +732,6 @@ def invalid_keyword_var_arg(self, typ: Type, context: Context) -> None: def undefined_in_superclass(self, member: str, context: Context) -> None: self.fail('"{}" undefined in superclass'.format(member), context) - def check_unusable_type(self, typ: Type, context: Context) -> bool: - """If type is a type which is not meant to be used (like Void or - NoneTyp(is_ret_type=True)), report an error such as '.. does not - return a value' and return True. Otherwise, return False. - """ - if (isinstance(typ, Void) or - (isinstance(typ, NoneTyp) and typ.is_ret_type)): - self.does_not_return_value(typ, context) - return True - else: - return False - def too_few_string_formatting_arguments(self, context: Context) -> None: self.fail('Not enough arguments for format string', context) diff --git a/mypy/sametypes.py b/mypy/sametypes.py index e3cc561944d1d..d3f283d449eaf 100644 --- a/mypy/sametypes.py +++ b/mypy/sametypes.py @@ -1,7 +1,7 @@ from typing import Sequence from mypy.types import ( - Type, UnboundType, ErrorType, AnyType, NoneTyp, Void, TupleType, TypedDictType, + Type, UnboundType, ErrorType, AnyType, NoneTyp, TupleType, TypedDictType, UnionType, CallableType, TypeVarType, Instance, TypeVisitor, ErasedType, TypeList, Overloaded, PartialType, DeletedType, UninhabitedType, TypeType ) @@ -64,9 +64,6 @@ def visit_type_list(self, t: TypeList) -> bool: def visit_any(self, left: AnyType) -> bool: return isinstance(self.right, AnyType) - def visit_void(self, left: Void) -> bool: - return isinstance(self.right, Void) - def visit_none_type(self, left: NoneTyp) -> bool: return isinstance(self.right, NoneTyp) diff --git a/mypy/solve.py b/mypy/solve.py index 07346f05ed963..dda9a0950b90a 100644 --- a/mypy/solve.py +++ b/mypy/solve.py @@ -3,7 +3,7 @@ from typing import List, Dict from collections import defaultdict -from mypy.types import Type, Void, NoneTyp, AnyType, ErrorType, UninhabitedType, TypeVarId +from mypy.types import Type, NoneTyp, AnyType, ErrorType, UninhabitedType, TypeVarId from mypy.constraints import Constraint, SUPERTYPE_OF from mypy.join import join_types from mypy.meet import meet_types @@ -57,12 +57,9 @@ def solve_constraints(vars: List[TypeVarId], constraints: List[Constraint], if top: candidate = top else: - # No constraints for type variable -- type 'None' is the most specific type. + # No constraints for type variable -- 'UninhabitedType' is the most specific type. if strict: - if experiments.STRICT_OPTIONAL: - candidate = UninhabitedType() - else: - candidate = NoneTyp() + candidate = UninhabitedType() else: candidate = AnyType() elif top is None: diff --git a/mypy/stats.py b/mypy/stats.py index 5d6df35fa05a8..2b809a6d6267e 100644 --- a/mypy/stats.py +++ b/mypy/stats.py @@ -7,7 +7,7 @@ from mypy.traverser import TraverserVisitor from mypy.types import ( - Type, AnyType, Instance, FunctionLike, TupleType, Void, TypeVarType, + Type, AnyType, Instance, FunctionLike, TupleType, TypeVarType, TypeQuery, ANY_TYPE_STRATEGY, CallableType ) from mypy import nodes @@ -177,8 +177,6 @@ def type(self, t: Type) -> None: self.num_generic += 1 else: self.num_simple += 1 - elif isinstance(t, Void): - self.num_simple += 1 elif isinstance(t, FunctionLike): self.num_function += 1 elif isinstance(t, TupleType): diff --git a/mypy/subtypes.py b/mypy/subtypes.py index 4865b58532966..c98bb8e8d144b 100644 --- a/mypy/subtypes.py +++ b/mypy/subtypes.py @@ -1,7 +1,7 @@ from typing import List, Optional, Dict, Callable from mypy.types import ( - Type, AnyType, UnboundType, TypeVisitor, ErrorType, FormalArgument, Void, NoneTyp, + Type, AnyType, UnboundType, TypeVisitor, ErrorType, FormalArgument, NoneTyp, Instance, TypeVarType, CallableType, TupleType, TypedDictType, UnionType, Overloaded, ErasedType, TypeList, PartialType, DeletedType, UninhabitedType, TypeType, is_named_instance ) @@ -79,19 +79,6 @@ def is_equivalent(a: Type, and is_subtype(b, a, type_parameter_checker, ignore_pos_arg_names=ignore_pos_arg_names)) -def satisfies_upper_bound(a: Type, upper_bound: Type) -> bool: - """Is 'a' valid value for a type variable with the given 'upper_bound'? - - Same as is_subtype except that Void is considered to be a subtype of - any upper_bound. This is needed in a case like - - def f(g: Callable[[], T]) -> T: ... - def h() -> None: ... - f(h) - """ - return isinstance(a, Void) or is_subtype(a, upper_bound) - - class SubtypeVisitor(TypeVisitor[bool]): def __init__(self, right: Type, @@ -116,18 +103,15 @@ def visit_type_list(self, t: TypeList) -> bool: def visit_any(self, left: AnyType) -> bool: return True - def visit_void(self, left: Void) -> bool: - return isinstance(self.right, Void) - def visit_none_type(self, left: NoneTyp) -> bool: if experiments.STRICT_OPTIONAL: return (isinstance(self.right, NoneTyp) or is_named_instance(self.right, 'builtins.object')) else: - return not isinstance(self.right, Void) + return True def visit_uninhabited_type(self, left: UninhabitedType) -> bool: - return not isinstance(self.right, Void) + return True def visit_erased_type(self, left: ErasedType) -> bool: return True diff --git a/mypy/test/testsolve.py b/mypy/test/testsolve.py index e407f75acd9a7..fcf19273ebe0a 100644 --- a/mypy/test/testsolve.py +++ b/mypy/test/testsolve.py @@ -64,37 +64,13 @@ def test_multiple_variables(self) -> None: def test_no_constraints_for_var(self) -> None: self.assert_solve([self.fx.t.id], [], - [self.fx.nonet]) + [self.fx.uninhabited]) self.assert_solve([self.fx.t.id, self.fx.s.id], [], - [self.fx.nonet, self.fx.nonet]) + [self.fx.uninhabited, self.fx.uninhabited]) self.assert_solve([self.fx.t.id, self.fx.s.id], [self.supc(self.fx.s, self.fx.a)], - [self.fx.nonet, (self.fx.a, self.fx.o)]) - - def test_void_constraints(self) -> None: - self.assert_solve([self.fx.t.id], - [self.supc(self.fx.t, self.fx.void)], - [(self.fx.void, self.fx.void)]) - self.assert_solve([self.fx.t.id], - [self.subc(self.fx.t, self.fx.void)], - [(self.fx.void, self.fx.void)]) - - # Both bounds void. - self.assert_solve([self.fx.t.id], - [self.supc(self.fx.t, self.fx.void), - self.subc(self.fx.t, self.fx.void)], - [(self.fx.void, self.fx.void)]) - - # Cannot infer any type. - self.assert_solve([self.fx.t.id], - [self.supc(self.fx.t, self.fx.a), - self.supc(self.fx.t, self.fx.void)], - [None]) - self.assert_solve([self.fx.t.id], - [self.subc(self.fx.t, self.fx.a), - self.subc(self.fx.t, self.fx.void)], - [None]) + [self.fx.uninhabited, (self.fx.a, self.fx.o)]) def test_simple_constraints_with_dynamic_type(self) -> None: self.assert_solve([self.fx.t.id], diff --git a/mypy/test/testsubtypes.py b/mypy/test/testsubtypes.py index 4121f669ada0a..2d03945398980 100644 --- a/mypy/test/testsubtypes.py +++ b/mypy/test/testsubtypes.py @@ -12,7 +12,7 @@ def set_up(self) -> None: self.fx_co = TypeFixture(COVARIANT) def test_trivial_cases(self) -> None: - for simple in self.fx_co.void, self.fx_co.a, self.fx_co.o, self.fx_co.b: + for simple in self.fx_co.a, self.fx_co.o, self.fx_co.b: self.assert_subtype(simple, simple) def test_instance_subtyping(self) -> None: @@ -84,8 +84,8 @@ def test_basic_callable_subtyping(self) -> None: self.assert_strict_subtype(self.fx.callable(self.fx.d, self.fx.b), self.fx.callable(self.fx.d, self.fx.a)) - self.assert_unrelated(self.fx.callable(self.fx.a, self.fx.a), - self.fx.callable(self.fx.a, self.fx.void)) + self.assert_strict_subtype(self.fx.callable(self.fx.a, self.fx.nonet), + self.fx.callable(self.fx.a, self.fx.a)) self.assert_unrelated( self.fx.callable(self.fx.a, self.fx.a, self.fx.a), @@ -184,7 +184,6 @@ def test_type_callable_subtyping(self) -> None: # * more generic interface subtyping test cases # * type variables # * tuple types - # * void type # * None type # * any type # * generic function types diff --git a/mypy/test/testtypes.py b/mypy/test/testtypes.py index ed22cbe6f0cee..9fc6a71b55949 100644 --- a/mypy/test/testtypes.py +++ b/mypy/test/testtypes.py @@ -10,7 +10,7 @@ from mypy.join import join_types, join_simple from mypy.meet import meet_types from mypy.types import ( - UnboundType, AnyType, Void, CallableType, TupleType, TypeVarDef, Type, + UnboundType, AnyType, CallableType, TupleType, TypeVarDef, Type, Instance, NoneTyp, ErrorType, Overloaded, TypeType, UnionType, UninhabitedType, true_only, false_only, TypeVarId ) @@ -38,9 +38,6 @@ def test_generic_unbound_type(self) -> None: u = UnboundType('Foo', [UnboundType('T'), AnyType()]) assert_equal(str(u), 'Foo?[T?, Any]') - def test_void_type(self) -> None: - assert_equal(str(Void(None)), 'void') - def test_callable_type(self) -> None: c = CallableType([self.x, self.y], [ARG_POS, ARG_POS], @@ -48,7 +45,7 @@ def test_callable_type(self) -> None: AnyType(), self.function) assert_equal(str(c), 'def (X?, Y?) -> Any') - c2 = CallableType([], [], [], Void(None), None) + c2 = CallableType([], [], [], NoneTyp(), None) assert_equal(str(c2), 'def ()') def test_callable_type_with_default_args(self) -> None: @@ -90,7 +87,7 @@ def test_generic_function_type(self) -> None: v = [TypeVarDef('Y', -1, None, self.fx.o), TypeVarDef('X', -2, None, self.fx.o)] - c2 = CallableType([], [], [], Void(None), self.function, name=None, variables=v) + c2 = CallableType([], [], [], NoneTyp(), self.function, name=None, variables=v) assert_equal(str(c2), 'def [Y, X] ()') @@ -103,7 +100,7 @@ def set_up(self) -> None: # expand_type def test_trivial_expand(self) -> None: - for t in (self.fx.a, self.fx.o, self.fx.t, self.fx.void, self.fx.nonet, + for t in (self.fx.a, self.fx.o, self.fx.t, self.fx.nonet, self.tuple(self.fx.a), self.callable([], self.fx.a, self.fx.a), self.fx.anyt): self.assert_expand(t, [], t) @@ -139,7 +136,7 @@ def assert_expand(self, # erase_type def test_trivial_erase(self) -> None: - for t in (self.fx.a, self.fx.o, self.fx.void, self.fx.nonet, + for t in (self.fx.a, self.fx.o, self.fx.nonet, self.fx.anyt, self.fx.err): self.assert_erase(t, t) @@ -156,11 +153,11 @@ def test_erase_with_tuple_type(self) -> None: def test_erase_with_function_type(self) -> None: self.assert_erase(self.fx.callable(self.fx.a, self.fx.b), - self.fx.callable_type(self.fx.void)) + self.fx.callable_type(self.fx.nonet)) def test_erase_with_type_object(self) -> None: self.assert_erase(self.fx.callable_type(self.fx.a, self.fx.b), - self.fx.callable_type(self.fx.void)) + self.fx.callable_type(self.fx.nonet)) def test_erase_with_type_type(self) -> None: self.assert_erase(self.fx.type_a, self.fx.type_a) @@ -363,7 +360,7 @@ def set_up(self) -> None: self.fx = TypeFixture() def test_trivial_cases(self) -> None: - for simple in self.fx.void, self.fx.a, self.fx.o, self.fx.b: + for simple in self.fx.a, self.fx.o, self.fx.b: self.assert_join(simple, simple, simple) def test_class_subtyping(self) -> None: @@ -409,17 +406,6 @@ def test_type_vars(self) -> None: self.assert_join(self.fx.s, self.fx.s, self.fx.s) self.assert_join(self.fx.t, self.fx.s, self.fx.o) - def test_void(self) -> None: - self.assert_join(self.fx.void, self.fx.void, self.fx.void) - self.assert_join(self.fx.void, self.fx.anyt, self.fx.anyt) - - # Join of any other type against void results in ErrorType, since there - # is no other meaningful result. - for t in [self.fx.a, self.fx.o, NoneTyp(), UnboundType('x'), - self.fx.t, self.tuple(), - self.callable(self.fx.a, self.fx.b)]: - self.assert_join(t, self.fx.void, self.fx.err) - def test_none(self) -> None: # Any type t joined with None results in t. for t in [NoneTyp(), self.fx.a, self.fx.o, UnboundType('x'), @@ -441,7 +427,7 @@ def test_unbound_type(self) -> None: def test_any_type(self) -> None: # Join against 'Any' type always results in 'Any'. for t in [self.fx.anyt, self.fx.a, self.fx.o, NoneTyp(), - UnboundType('x'), self.fx.void, self.fx.t, self.tuple(), + UnboundType('x'), self.fx.t, self.tuple(), self.callable(self.fx.a, self.fx.b)]: self.assert_join(t, self.fx.anyt, self.fx.anyt) @@ -475,7 +461,7 @@ def test_error_type(self) -> None: # Meet against any type except dynamic results in ErrorType. for t in [self.fx.a, self.fx.o, NoneTyp(), UnboundType('x'), - self.fx.void, self.fx.t, self.tuple(), + self.fx.t, self.tuple(), self.callable(self.fx.a, self.fx.b)]: self.assert_join(t, self.fx.err, self.fx.err) @@ -651,7 +637,7 @@ def set_up(self) -> None: self.fx = TypeFixture() def test_trivial_cases(self) -> None: - for simple in self.fx.void, self.fx.a, self.fx.o, self.fx.b: + for simple in self.fx.a, self.fx.o, self.fx.b: self.assert_meet(simple, simple, simple) def test_class_subtyping(self) -> None: @@ -694,25 +680,12 @@ def test_type_vars(self) -> None: self.assert_meet(self.fx.s, self.fx.s, self.fx.s) self.assert_meet(self.fx.t, self.fx.s, NoneTyp()) - def test_void(self) -> None: - self.assert_meet(self.fx.void, self.fx.void, self.fx.void) - self.assert_meet(self.fx.void, self.fx.anyt, self.fx.void) - - # Meet of any other type against void results in ErrorType, since there - # is no meaningful valid result. - for t in [self.fx.a, self.fx.o, UnboundType('x'), NoneTyp(), - self.fx.t, self.tuple(), - self.callable(self.fx.a, self.fx.b)]: - self.assert_meet(t, self.fx.void, self.fx.err) - def test_none(self) -> None: self.assert_meet(NoneTyp(), NoneTyp(), NoneTyp()) self.assert_meet(NoneTyp(), self.fx.anyt, NoneTyp()) - self.assert_meet(NoneTyp(), self.fx.void, self.fx.err) - # Any type t joined with None results in None, unless t is any or - # void. + # Any type t joined with None results in None, unless t is Any. for t in [self.fx.a, self.fx.o, UnboundType('x'), self.fx.t, self.tuple(), self.callable(self.fx.a, self.fx.b)]: self.assert_meet(t, NoneTyp(), NoneTyp()) @@ -721,12 +694,11 @@ def test_unbound_type(self) -> None: self.assert_meet(UnboundType('x'), UnboundType('x'), self.fx.anyt) self.assert_meet(UnboundType('x'), UnboundType('y'), self.fx.anyt) - self.assert_meet(UnboundType('x'), self.fx.void, self.fx.err) self.assert_meet(UnboundType('x'), self.fx.anyt, UnboundType('x')) - # The meet of any type t with an unbound type results in dynamic - # (except for void). Unbound type means that there is an error - # somewhere in the program, so this does not affect type safety. + # The meet of any type t with an unbound type results in dynamic. + # Unbound type means that there is an error somewhere in the program, + # so this does not affect type safety. for t in [self.fx.a, self.fx.o, self.fx.t, self.tuple(), self.callable(self.fx.a, self.fx.b)]: self.assert_meet(t, UnboundType('X'), self.fx.anyt) @@ -734,7 +706,7 @@ def test_unbound_type(self) -> None: def test_dynamic_type(self) -> None: # Meet against dynamic type always results in dynamic. for t in [self.fx.anyt, self.fx.a, self.fx.o, NoneTyp(), - UnboundType('x'), self.fx.void, self.fx.t, self.tuple(), + UnboundType('x'), self.fx.t, self.tuple(), self.callable(self.fx.a, self.fx.b)]: self.assert_meet(t, self.fx.anyt, t) @@ -743,7 +715,7 @@ def test_error_type(self) -> None: # Meet against any type except dynamic results in ErrorType. for t in [self.fx.a, self.fx.o, NoneTyp(), UnboundType('x'), - self.fx.void, self.fx.t, self.tuple(), + self.fx.t, self.tuple(), self.callable(self.fx.a, self.fx.b)]: self.assert_meet(t, self.fx.err, self.fx.err) diff --git a/mypy/typeanal.py b/mypy/typeanal.py index 191b9c7f55edf..e33daa2eed3c6 100644 --- a/mypy/typeanal.py +++ b/mypy/typeanal.py @@ -4,8 +4,8 @@ from typing import Callable, List, Optional, Set from mypy.types import ( - Type, UnboundType, TypeVarType, TupleType, TypedDictType, UnionType, Instance, TypeVarId, - AnyType, CallableType, Void, NoneTyp, DeletedType, TypeList, TypeVarDef, TypeVisitor, + Type, UnboundType, TypeVarType, TupleType, TypedDictType, UnionType, Instance, + AnyType, CallableType, NoneTyp, DeletedType, TypeList, TypeVarDef, TypeVisitor, StarType, PartialType, EllipsisType, UninhabitedType, TypeType, get_typ_args, set_typ_args, get_type_vars, ) @@ -16,7 +16,7 @@ ) from mypy.sametypes import is_same_type from mypy.exprtotype import expr_to_unanalyzed_type, TypeTranslationError -from mypy.subtypes import satisfies_upper_bound +from mypy.subtypes import is_subtype from mypy import nodes from mypy import experiments @@ -128,10 +128,7 @@ def visit_unbound_type(self, t: UnboundType) -> Type: assert sym.tvar_def is not None return TypeVarType(sym.tvar_def, t.line) elif fullname == 'builtins.None': - if experiments.STRICT_OPTIONAL: - return NoneTyp(is_ret_type=t.is_ret_type) - else: - return Void() + return NoneTyp() elif fullname == 'typing.Any': return AnyType() elif fullname == 'typing.Tuple': @@ -146,18 +143,15 @@ def visit_unbound_type(self, t: UnboundType) -> Type: return self.tuple_type(self.anal_array(t.args)) elif fullname == 'typing.Union': items = self.anal_array(t.args) - items = [item for item in items if not isinstance(item, Void)] + if not experiments.STRICT_OPTIONAL: + items = [item for item in items if not isinstance(item, NoneTyp)] return UnionType.make_union(items) elif fullname == 'typing.Optional': if len(t.args) != 1: self.fail('Optional[...] must have exactly one type argument', t) return AnyType() item = self.anal_type(t.args[0]) - if experiments.STRICT_OPTIONAL: - return UnionType.make_simplified_union([item, NoneTyp()]) - else: - # Without strict Optional checking Optional[t] is just an alias for t. - return item + return UnionType.make_simplified_union([item, NoneTyp()]) elif fullname == 'typing.Callable': return self.analyze_callable_type(t) elif fullname == 'typing.Type': @@ -299,9 +293,6 @@ def replace_alias_tvars(self, tp: Type, vars: List[str], subs: List[Type], def visit_any(self, t: AnyType) -> Type: return t - def visit_void(self, t: Void) -> Type: - return t - def visit_none_type(self, t: NoneTyp) -> Type: return t @@ -499,7 +490,7 @@ def visit_instance(self, t: Instance) -> None: arg_values = [arg] self.check_type_var_values(info, arg_values, TypeVar.values, i + 1, t) - if not satisfies_upper_bound(arg, TypeVar.upper_bound): + if not is_subtype(arg, TypeVar.upper_bound): self.fail('Type argument "{}" of "{}" must be ' 'a subtype of "{}"'.format( arg, info.name(), TypeVar.upper_bound), t) @@ -546,9 +537,6 @@ def visit_unbound_type(self, t: UnboundType) -> None: def visit_any(self, t: AnyType) -> None: pass - def visit_void(self, t: Void) -> None: - pass - def visit_none_type(self, t: NoneTyp) -> None: pass diff --git a/mypy/typefixture.py b/mypy/typefixture.py index 8afcfac5f119b..23089419215dc 100644 --- a/mypy/typefixture.py +++ b/mypy/typefixture.py @@ -6,8 +6,8 @@ from typing import List from mypy.types import ( - Type, TypeVarType, AnyType, Void, ErrorType, NoneTyp, - Instance, CallableType, TypeVarDef, TypeType, + Type, TypeVarType, AnyType, ErrorType, NoneTyp, + Instance, CallableType, TypeVarDef, TypeType, UninhabitedType ) from mypy.nodes import ( TypeInfo, ClassDef, Block, ARG_POS, ARG_OPT, ARG_STAR, SymbolTable, @@ -41,9 +41,9 @@ def make_type_var(name: str, id: int, values: List[Type], upper_bound: Type, # Simple types self.anyt = AnyType() - self.void = Void() self.err = ErrorType() self.nonet = NoneTyp() + self.uninhabited = UninhabitedType() # Abstract class TypeInfos diff --git a/mypy/types.py b/mypy/types.py index 8c90696079b81..9621c0f859fad 100644 --- a/mypy/types.py +++ b/mypy/types.py @@ -14,7 +14,6 @@ ARG_POS, ARG_OPT, ARG_STAR, ARG_STAR2, ARG_NAMED, ARG_NAMED_OPT, ) -from mypy import experiments from mypy.sharedparse import argument_elide_name @@ -189,8 +188,6 @@ class UnboundType(Type): args = None # type: List[Type] # should this type be wrapped in an Optional? optional = False - # is this type a return type? - is_ret_type = False # special case for X[()] empty_tuple_index = False @@ -201,14 +198,12 @@ def __init__(self, line: int = -1, column: int = -1, optional: bool = False, - is_ret_type: bool = False, empty_tuple_index: bool = False) -> None: if not args: args = [] self.name = name self.args = args self.optional = optional - self.is_ret_type = is_ret_type self.empty_tuple_index = empty_tuple_index super().__init__(line, column) @@ -282,44 +277,15 @@ def deserialize(cls, data: JsonDict) -> 'AnyType': return AnyType() -class Void(Type): - """The return type 'None'. - - This can only be used as the return type in a callable type and as - the result type of calling such callable. - """ - - can_be_true = False - source = '' # May be None; function that generated this value - - def __init__(self, source: str = None, line: int = -1, column: int = -1) -> None: - self.source = source - super().__init__(line, column) - - def accept(self, visitor: 'TypeVisitor[T]') -> T: - return visitor.visit_void(self) - - def with_source(self, source: str) -> 'Void': - return Void(source, self.line, self.column) - - def serialize(self) -> JsonDict: - return {'.class': 'Void'} - - @classmethod - def deserialize(cls, data: JsonDict) -> 'Void': - assert data['.class'] == 'Void' - return Void() - - class UninhabitedType(Type): """This type has no members. - This type is almost the bottom type, except it is not a subtype of Void. + This type is the bottom type. With strict Optional checking, it is the only common subtype between all other types, which allows `meet` to be well defined. Without strict Optional checking, NoneTyp fills this role. - In general, for any type T that isn't Void: + In general, for any type T: join(UninhabitedType, T) = T meet(UninhabitedType, T) = UninhabitedType is_subtype(UninhabitedType, T) = True @@ -349,39 +315,24 @@ def deserialize(cls, data: JsonDict) -> 'UninhabitedType': class NoneTyp(Type): """The type of 'None'. - Without strict Optional checking: - This is only used internally during type inference. Programs - cannot declare a variable of this type, and the type checker - refuses to infer this type for a variable. However, subexpressions - often have this type. Note that this is not used as the result - type when calling a function with a void type, even though - semantically such a function returns a None value; the void type - is used instead so that we can report an error if the caller tries - to do anything with the return value. - - With strict Optional checking: - This type can be written by users as 'None', except as the return value - of a function, where 'None' means Void. + This type can be written by users as 'None'. """ can_be_true = False - def __init__(self, is_ret_type: bool = False, line: int = -1, column: int = -1) -> None: + def __init__(self, line: int = -1, column: int = -1) -> None: super().__init__(line, column) - self.is_ret_type = is_ret_type def accept(self, visitor: 'TypeVisitor[T]') -> T: return visitor.visit_none_type(self) def serialize(self) -> JsonDict: - return {'.class': 'NoneTyp', - 'is_ret_type': self.is_ret_type, - } + return {'.class': 'NoneTyp'} @classmethod def deserialize(cls, data: JsonDict) -> 'NoneTyp': assert data['.class'] == 'NoneTyp' - return NoneTyp(is_ret_type=data['is_ret_type']) + return NoneTyp() class ErasedType(Type): @@ -546,6 +497,9 @@ def items(self) -> List['CallableType']: pass @abstractmethod def with_name(self, name: str) -> 'FunctionLike': pass + @abstractmethod + def get_name(self) -> str: pass + # Corresponding instance type (e.g. builtins.type) fallback = None # type: Instance @@ -670,10 +624,10 @@ def accept(self, visitor: 'TypeVisitor[T]') -> T: def with_name(self, name: str) -> 'CallableType': """Return a copy of this type with the specified name.""" - ret = self.ret_type - if isinstance(ret, Void): - ret = ret.with_source(name) - return self.copy_modified(ret_type=ret, name=name) + return self.copy_modified(ret_type=self.ret_type, name=name) + + def get_name(self) -> str: + return self.name def max_fixed_args(self) -> int: n = len(self.arg_types) @@ -821,7 +775,7 @@ def items(self) -> List[CallableType]: return self._items def name(self) -> str: - return self._items[0].name + return self.get_name() def is_type_obj(self) -> bool: # All the items must have the same type object status, so it's @@ -839,6 +793,9 @@ def with_name(self, name: str) -> 'Overloaded': ni.append(it.with_name(name)) return Overloaded(ni) + def get_name(self) -> str: + return self._items[0].name + def accept(self, visitor: 'TypeVisitor[T]') -> T: return visitor.visit_overloaded(self) @@ -1025,10 +982,7 @@ def make_union(items: List[Type], line: int = -1, column: int = -1) -> Type: elif len(items) == 1: return items[0] else: - if experiments.STRICT_OPTIONAL: - return UninhabitedType() - else: - return Void() + return UninhabitedType() @staticmethod def make_simplified_union(items: List[Type], line: int = -1, column: int = -1) -> Type: @@ -1227,10 +1181,6 @@ def visit_error_type(self, t: ErrorType) -> T: def visit_any(self, t: AnyType) -> T: pass - @abstractmethod - def visit_void(self, t: Void) -> T: - pass - @abstractmethod def visit_none_type(self, t: NoneTyp) -> T: pass @@ -1307,9 +1257,6 @@ def visit_error_type(self, t: ErrorType) -> Type: def visit_any(self, t: AnyType) -> Type: return t - def visit_void(self, t: Void) -> Type: - return t - def visit_none_type(self, t: NoneTyp) -> Type: return t @@ -1409,9 +1356,6 @@ def visit_error_type(self, t: ErrorType) -> str: def visit_any(self, t: AnyType) -> str: return 'Any' - def visit_void(self, t: Void) -> str: - return 'void' - def visit_none_type(self, t: NoneTyp) -> str: # Fully qualify to make this distinct from the None value. return "builtins.None" @@ -1468,7 +1412,7 @@ def visit_callable_type(self, t: CallableType) -> str: s = '({})'.format(s) - if not isinstance(t.ret_type, Void): + if not isinstance(t.ret_type, NoneTyp): s += ' -> {}'.format(t.ret_type) if t.variables: @@ -1581,9 +1525,6 @@ def visit_error_type(self, t: ErrorType) -> bool: def visit_any(self, t: AnyType) -> bool: return self.default - def visit_void(self, t: Void) -> bool: - return self.default - def visit_uninhabited_type(self, t: UninhabitedType) -> bool: return self.default diff --git a/test-data/unit/check-async-await.test b/test-data/unit/check-async-await.test index ebae58ee6b1d9..3c2f4c6b84baf 100644 --- a/test-data/unit/check-async-await.test +++ b/test-data/unit/check-async-await.test @@ -282,7 +282,7 @@ class C: def __aenter__(self) -> None: pass async def __aexit__(self, x, y, z) -> None: pass async def f() -> None: - async with C() as x: # E: "__aenter__" of "C" does not return a value + async with C() as x: # E: None has no attribute "__await__" pass [builtins fixtures/async_await.pyi] [out] @@ -304,7 +304,7 @@ class C: async def __aenter__(self) -> int: pass def __aexit__(self, x, y, z) -> None: pass async def f() -> None: - async with C() as x: # E: "__aexit__" of "C" does not return a value + async with C() as x: # E: None has no attribute "__await__" pass [builtins fixtures/async_await.pyi] [out] @@ -425,8 +425,8 @@ async def g() -> AsyncGenerator[int, None]: yield 'not an int' # E: Incompatible types in yield (actual type "str", expected type "int") # return without a value is fine return -reveal_type(g) # E: Revealed type is 'def () -> typing.AsyncGenerator[builtins.int, void]' -reveal_type(g()) # E: Revealed type is 'typing.AsyncGenerator[builtins.int, void]' +reveal_type(g) # E: Revealed type is 'def () -> typing.AsyncGenerator[builtins.int, builtins.None]' +reveal_type(g()) # E: Revealed type is 'typing.AsyncGenerator[builtins.int, builtins.None]' async def h() -> None: async for item in g(): @@ -463,7 +463,7 @@ async def genfunc() -> AsyncGenerator[int, None]: async def user() -> None: gen = genfunc() - reveal_type(gen.__aiter__()) # E: Revealed type is 'typing.AsyncGenerator[builtins.int*, void]' + reveal_type(gen.__aiter__()) # E: Revealed type is 'typing.AsyncGenerator[builtins.int*, builtins.None]' reveal_type(await gen.__anext__()) # E: Revealed type is 'builtins.int*' diff --git a/test-data/unit/check-bound.test b/test-data/unit/check-bound.test index ee935aed8bdd5..b51b9c2133a0e 100644 --- a/test-data/unit/check-bound.test +++ b/test-data/unit/check-bound.test @@ -56,7 +56,7 @@ class C(Generic[T]): return self.t c1 = None # type: C[None] c1.get() -d = c1.get() # E: Function does not return a value +d = c1.get() # E: "get" of "C" does not return a value [case testBoundAny] @@ -82,7 +82,7 @@ def f(g: Callable[[], T]) -> T: return g() def h() -> None: pass f(h) -a = f(h) # E: "h" does not return a value +a = f(h) # E: "f" does not return a value [case testBoundInheritance] diff --git a/test-data/unit/check-classes.test b/test-data/unit/check-classes.test index 54b737ad16e8f..d841394196a5f 100644 --- a/test-data/unit/check-classes.test +++ b/test-data/unit/check-classes.test @@ -281,10 +281,9 @@ class A: def g(self) -> 'A': pass class B(A): def f(self) -> A: pass # Fail - def g(self) -> None: pass # Fail + def g(self) -> None: pass [out] main:6: error: Return type of "f" incompatible with supertype "A" -main:7: error: Return type of "g" incompatible with supertype "A" [case testOverride__new__WithDifferentSignature] class A: @@ -727,12 +726,9 @@ import typing class A: def f(self) -> None: def g() -> None: - a = None - b = None + "" + 1 # E: Unsupported operand types for + ("str" and "int") + "" + 1 # E: Unsupported operand types for + ("str" and "int") [out] -main:5: error: Need type annotation for variable -main:6: error: Need type annotation for variable - -- Static methods -- -------------- diff --git a/test-data/unit/check-dynamic-typing.test b/test-data/unit/check-dynamic-typing.test index 27f8bee9f1c8e..9529a421977a0 100644 --- a/test-data/unit/check-dynamic-typing.test +++ b/test-data/unit/check-dynamic-typing.test @@ -537,7 +537,7 @@ f11 = None # type: Callable[[], Any] f2 = None # type: Callable[[], A] f3 = None # type: Callable[[], None] -f2 = f3 # E: Incompatible types in assignment (expression has type Callable[[], None], variable has type Callable[[], A]) +f2 = f3 f1 = f2 f1 = f3 diff --git a/test-data/unit/check-expressions.test b/test-data/unit/check-expressions.test index 664fe6bfe5e76..4e3c5a7034c95 100644 --- a/test-data/unit/check-expressions.test +++ b/test-data/unit/check-expressions.test @@ -921,8 +921,8 @@ a = None # type: A f() + a # E: "f" does not return a value a + f() # E: "f" does not return a value f() == a # E: "f" does not return a value -a != f() # E: Unsupported left operand type for != ("A") -cast(A, f()) # E: "f" does not return a value +a != f() # E: "f" does not return a value +cast(A, f()) f().foo # E: "f" does not return a value def f() -> None: pass @@ -933,9 +933,9 @@ class A: [case testNoneReturnTypeWithExpressions2] a, b = None, None # type: (A, bool) -a < f() # E: Unsupported left operand type for < ("A") +f() in a # Fail (see output) +a < f() # E: "f" does not return a value f() <= a # E: "f" does not return a value -f() in a # E: Unsupported right operand type for in ("A") a in f() # E: "f" does not return a value -f() # E: "f" does not return a value not f() # E: "f" does not return a value @@ -947,6 +947,9 @@ class A: def __add__(self, x: 'A') -> 'A': pass [builtins fixtures/bool.pyi] +[out] +main:3: error: "f" does not return a value +main:3: error: Unsupported right operand type for in ("A") -- Slicing @@ -1474,6 +1477,7 @@ def f(x: int) -> None: [out] main:1: error: The return type of a generator function should be "Generator" or one of its supertypes main:2: error: Argument 1 to "f" has incompatible type "str"; expected "int" +main:2: error: "f" does not return a value [case testYieldExpressionWithNone] from typing import Iterator diff --git a/test-data/unit/check-functions.test b/test-data/unit/check-functions.test index 8060986910f01..d8a8cf6f58ea5 100644 --- a/test-data/unit/check-functions.test +++ b/test-data/unit/check-functions.test @@ -208,7 +208,7 @@ from typing import Callable f = None # type: Callable[[], None] g = None # type: Callable[[], object] f = g # E: Incompatible types in assignment (expression has type Callable[[], object], variable has type Callable[[], None]) -g = f # E: Incompatible types in assignment (expression has type Callable[[], None], variable has type Callable[[], object]) +g = f # OK f = f g = g diff --git a/test-data/unit/check-generic-subtyping.test b/test-data/unit/check-generic-subtyping.test index 35cd0f99a4ccb..94c9d33482136 100644 --- a/test-data/unit/check-generic-subtyping.test +++ b/test-data/unit/check-generic-subtyping.test @@ -394,7 +394,7 @@ B(1) C(1) C('a') # E: Argument 1 to "C" has incompatible type "str"; expected "int" D(A(1)) -D(1) # E: Argument 1 to "D" has incompatible type "int"; expected A[None] +D(1) # E: Argument 1 to "D" has incompatible type "int"; expected A[] [case testInheritedConstructor2] diff --git a/test-data/unit/check-generics.test b/test-data/unit/check-generics.test index f6613701ec51e..e1efd0a3f559e 100644 --- a/test-data/unit/check-generics.test +++ b/test-data/unit/check-generics.test @@ -565,7 +565,7 @@ def func(x: IntNode[T]) -> IntNode[T]: return x reveal_type(func) # E: Revealed type is 'def [T] (x: __main__.Node[builtins.int, T`-1]) -> __main__.Node[builtins.int, T`-1]' -func(1) # E: Argument 1 to "func" has incompatible type "int"; expected Node[int, None] +func(1) # E: Argument 1 to "func" has incompatible type "int"; expected Node[int, ] func(Node('x', 1)) # E: Argument 1 to "Node" has incompatible type "str"; expected "int" reveal_type(func(Node(1, 'x'))) # E: Revealed type is '__main__.Node[builtins.int, builtins.str*]' @@ -800,7 +800,7 @@ reveal_type(x) # E: Revealed type is 'builtins.int' def f2(x: IntTP[T]) -> IntTP[T]: return x -f2((1, 2, 3)) # E: Argument 1 to "f2" has incompatible type "Tuple[int, int, int]"; expected "Tuple[int, None]" +f2((1, 2, 3)) # E: Argument 1 to "f2" has incompatible type "Tuple[int, int, int]"; expected "Tuple[int, ]" reveal_type(f2((1, 'x'))) # E: Revealed type is 'Tuple[builtins.int, builtins.str*]' [builtins fixtures/for.pyi] @@ -869,7 +869,7 @@ n.y = 'x' # E: Incompatible types in assignment (expression has type "str", vari def f(x: Node[T, T]) -> TupledNode[T]: return Node(x.x, (x.x, x.x)) -f(1) # E: Argument 1 to "f" has incompatible type "int"; expected Node[None, None] +f(1) # E: Argument 1 to "f" has incompatible type "int"; expected Node[, ] f(Node(1, 'x')) # E: Cannot infer type argument 1 of "f" reveal_type(Node('x', 'x')) # E: Revealed type is 'a.Node[builtins.str*, builtins.str*]' diff --git a/test-data/unit/check-inference-context.test b/test-data/unit/check-inference-context.test index f93429e82130e..5e4b8d7322b5e 100644 --- a/test-data/unit/check-inference-context.test +++ b/test-data/unit/check-inference-context.test @@ -13,7 +13,7 @@ b = None # type: B ao = f() ab = f() -b = f() # E: Incompatible types in assignment (expression has type A[None], variable has type "B") +b = f() # E: Incompatible types in assignment (expression has type A[], variable has type "B") def f() -> 'A[T]': pass @@ -29,7 +29,7 @@ b = None # type: B ao = A() ab = A() -b = A() # E: Incompatible types in assignment (expression has type A[None], variable has type "B") +b = A() # E: Incompatible types in assignment (expression has type A[], variable has type "B") class A(Generic[T]): pass class B: pass @@ -334,7 +334,7 @@ aa = None # type: List[A] ao = None # type: List[object] a = None # type: A -a = [] # E: Incompatible types in assignment (expression has type List[None], variable has type "A") +a = [] # E: Incompatible types in assignment (expression has type List[], variable has type "A") aa = [] ao = [] @@ -385,7 +385,7 @@ class B(A): pass import typing def f() -> None: a = [] # E: Need type annotation for variable - b = [None] # E: Need type annotation for variable + b = [None] c = [B()] c = [object()] # E: List item 0 has incompatible type "object" c = [B()] @@ -755,7 +755,7 @@ T = TypeVar('T') def f(x: Union[List[T], str]) -> None: pass f([1]) f('') -f(1) # E: Argument 1 to "f" has incompatible type "int"; expected "Union[List[None], str]" +f(1) # E: Argument 1 to "f" has incompatible type "int"; expected "Union[List[], str]" [builtins fixtures/isinstancelist.pyi] [case testIgnoringInferenceContext] @@ -824,7 +824,7 @@ from typing import TypeVar, Callable, Generic T = TypeVar('T') class A(Generic[T]): pass -reveal_type(A()) # E: Revealed type is '__main__.A[builtins.None]' +reveal_type(A()) # E: Revealed type is '__main__.A[]' b = reveal_type(A()) # type: A[int] # E: Revealed type is '__main__.A[builtins.int]' [case testUnionWithGenericTypeItemContext] @@ -877,4 +877,17 @@ class M(Generic[_KT, _VT]): def get(self, k: _KT, default: _T) -> _T: ... def f(d: M[_KT, _VT], k: _KT) -> _VT: + return d.get(k, None) # E: "get" of "M" does not return a value + +[case testGenericMethodCalledInGenericContext2] +from typing import TypeVar, Generic, Union + +_KT = TypeVar('_KT') +_VT = TypeVar('_VT') +_T = TypeVar('_T') + +class M(Generic[_KT, _VT]): + def get(self, k: _KT, default: _T) -> Union[_VT, _T]: ... + +def f(d: M[_KT, _VT], k: _KT) -> Union[_VT, None]: return d.get(k, None) diff --git a/test-data/unit/check-inference.test b/test-data/unit/check-inference.test index c90d2c0d4c0c7..6ba5a478596bc 100644 --- a/test-data/unit/check-inference.test +++ b/test-data/unit/check-inference.test @@ -109,8 +109,8 @@ class B: pass [case testInferringTupleTypeForLvarWithNones] import typing def f() -> None: - a = A(), None # E: Need type annotation for variable - b = None, A() # E: Need type annotation for variable + a = A(), None + b = None, A() class A: pass [builtins fixtures/tuple.pyi] @@ -246,8 +246,8 @@ class C: pass [case testInferringLvarTypesInMultiDefWithNoneTypes] import typing def f() -> None: - a, b = A(), None # E: Need type annotation for variable - c, d = None, A() # E: Need type annotation for variable + a, b = A(), None + c, d = None, A() class A: pass [out] @@ -255,7 +255,7 @@ class A: pass [case testInferringLvarTypesInNestedTupleAssignmentWithNoneTypes] import typing def f() -> None: - a1, (a2, b) = A(), (A(), None) # E: Need type annotation for variable + a1, (a2, b) = A(), (A(), None) class A: pass [out] @@ -413,7 +413,7 @@ def id(x: T) -> T: return x [out] -[case testUnderspecifiedInferenceResult] +[case testUnderspecifiedInferenceResult-skip] from typing import TypeVar T = TypeVar('T') class A: pass @@ -430,19 +430,6 @@ def f() -> T: pass def g(a: T) -> None: pass [out] -[case testUnsolvableInferenceResult] -from typing import TypeVar -T = TypeVar('T') -f(A(), g()) # Fail -f(A(), A()) - -def f(a: T, b: T) -> None: pass -def g() -> None: pass -class A: pass -[out] -main:3: error: Cannot infer type argument 1 of "f" -main:3: error: "g" does not return a value - [case testInferenceWithMultipleConstraints] from typing import TypeVar T = TypeVar('T') @@ -694,10 +681,10 @@ g('a')() # E: List[str] not callable # The next line is a case where there are multiple ways to satisfy a constraint # involving a Union. Either T = List[str] or T = str would turn out to be valid, # but mypy doesn't know how to branch on these two options (and potentially have -# to backtrack later) and defaults to T = None. The result is an awkward error -# message. Either a better error message, or simply accepting the call, would be -# preferable here. -g(['a']) # E: Argument 1 to "g" has incompatible type List[str]; expected List[None] +# to backtrack later) and defaults to T = . The result is an +# awkward error message. Either a better error message, or simply accepting the +# call, would be preferable here. +g(['a']) # E: Argument 1 to "g" has incompatible type List[str]; expected List[] h(g(['a'])) @@ -744,7 +731,7 @@ from typing import TypeVar, Union, List T = TypeVar('T') def f() -> List[T]: pass d1 = f() # type: Union[List[int], str] -d2 = f() # type: Union[int, str] # E: Incompatible types in assignment (expression has type List[None], variable has type "Union[int, str]") +d2 = f() # type: Union[int, str] # E: Incompatible types in assignment (expression has type List[], variable has type "Union[int, str]") def g(x: T) -> List[T]: pass d3 = g(1) # type: Union[List[int], List[str]] [builtins fixtures/list.pyi] @@ -840,8 +827,9 @@ for x in [A()]: b = x # E: Incompatible types in assignment (expression has type "A", variable has type "B") a = x -for y in []: # E: Need type annotation for variable +for y in []: a = y + reveal_type(y) # E: Revealed type is 'builtins.None' class A: pass class B: pass @@ -861,7 +849,7 @@ for xx, yy, zz in [(A(), B())]: # Fail pass for xx, (yy, zz) in [(A(), B())]: # Fail pass -for xxx, yyy in [(None, None)]: # Fail +for xxx, yyy in [(None, None)]: pass class A: pass @@ -874,7 +862,6 @@ main:5: error: Incompatible types in assignment (expression has type "B", variab main:6: error: Incompatible types in assignment (expression has type "C", variable has type "A") main:10: error: Need more than 2 values to unpack (3 expected) main:12: error: '__main__.B' object is not iterable -main:14: error: Need type annotation for variable [case testInferenceOfFor3] @@ -886,8 +873,9 @@ for x, y in [[A()]]: a = x a = y -for e, f in [[]]: # E: Need type annotation for variable - pass +for e, f in [[]]: + reveal_type(e) # E: Revealed type is 'builtins.None' + reveal_type(f) # E: Revealed type is 'builtins.None' class A: pass class B: pass @@ -1073,10 +1061,10 @@ def f(x: Callable[[], None]) -> None: pass def g(x: Callable[[], int]) -> None: pass a = lambda: None f(a) -g(a) # E: Argument 1 to "g" has incompatible type Callable[[], None]; expected Callable[[], int] +g(a) b = lambda: None # type: Callable[[], None] f(b) -g(b) # E: Argument 1 to "g" has incompatible type Callable[[], None]; expected Callable[[], int] +g(b) [case testLambdaDefaultContext] # flags: --strict-optional @@ -1383,7 +1371,7 @@ def f() -> None: [case testLvarInitializedToNoneWithoutType] import typing def f() -> None: - a = None # E: Need type annotation for variable + a = None a.x() # E: None has no attribute "x" [out] @@ -1419,7 +1407,8 @@ def f() -> None: [builtins fixtures/list.pyi] [out] -[case testPartiallyInitializedToNoneAndThenToIncompleteType] +[case testPartiallyInitializedToNoneAndThenToIncompleteType-skip] +# TODO(ddfisher): fix partial type bug and re-enable from typing import TypeVar, Dict T = TypeVar('T') def f(*x: T) -> Dict[int, T]: pass @@ -1430,12 +1419,13 @@ if object(): [case testPartiallyInitializedVariableDoesNotEscapeScope1] def f() -> None: - x = None # E: Need type annotation for variable + x = None + reveal_type(x) # E: Revealed type is 'builtins.None' x = 1 [out] [case testPartiallyInitializedVariableDoesNotEscapeScope2] -x = None # E: Need type annotation for variable +x = None def f() -> None: x = None x = 1 @@ -1458,8 +1448,8 @@ class A: self.x = 1 self.x() [out] -main:3: error: Need type annotation for variable -main:7: error: "int" not callable +main:6: error: Incompatible types in assignment (expression has type "int", variable has type None) +main:7: error: None not callable [case testGlobalInitializedToNoneSetFromFunction] a = None @@ -1488,7 +1478,6 @@ class A: pass [builtins fixtures/for.pyi] [out] -main:3: error: Need type annotation for variable main:5: error: None has no attribute "__iter__" [case testPartialTypeErrorSpecialCase2] @@ -1510,7 +1499,6 @@ class A: pass [builtins fixtures/for.pyi] [out] -main:2: error: Need type annotation for variable main:4: error: None has no attribute "__iter__" diff --git a/test-data/unit/check-modules.test b/test-data/unit/check-modules.test index 2444ce78cf883..b4312de38ea3f 100644 --- a/test-data/unit/check-modules.test +++ b/test-data/unit/check-modules.test @@ -491,7 +491,7 @@ x = 1 [case testAssignToFuncDefViaImport] from m import * # E: Incompatible import of "x" (imported name has type "int", local name has type "str") -f = None # E: Need type annotation for variable +f = None x = '' [file m.py] def f(): pass diff --git a/test-data/unit/check-optional.test b/test-data/unit/check-optional.test index f6850d6bb2f02..d5f2c06aebf4b 100644 --- a/test-data/unit/check-optional.test +++ b/test-data/unit/check-optional.test @@ -335,9 +335,9 @@ def f() -> None: def g(x: Optional[int]) -> int: pass -x = f() # E: Function does not return a value -f() + 1 # E: Function does not return a value -g(f()) # E: Function does not return a value +x = f() # E: "f" does not return a value +f() + 1 # E: "f" does not return a value +g(f()) # E: "f" does not return a value [case testEmptyReturn] def f() -> None: diff --git a/test-data/unit/check-statements.test b/test-data/unit/check-statements.test index e42e2730028d4..eb0d7e194aaa1 100644 --- a/test-data/unit/check-statements.test +++ b/test-data/unit/check-statements.test @@ -44,7 +44,7 @@ import typing def f() -> None: return None def g() -> None: - return f() # E: No return value expected + return f() [out] [case testReturnInGenerator] @@ -1127,7 +1127,7 @@ def f() -> Iterator[int]: [case testYieldWithExplicitNone] from typing import Iterator def f() -> Iterator[None]: - yield None # E: Incompatible types in yield (actual type None, expected type None) + yield None [builtins fixtures/for.pyi] [out] diff --git a/test-data/unit/check-tuples.test b/test-data/unit/check-tuples.test index b682d18462318..c836fe8cd41e1 100644 --- a/test-data/unit/check-tuples.test +++ b/test-data/unit/check-tuples.test @@ -633,13 +633,13 @@ for x in t: [case testForLoopOverEmptyTuple] import typing t = () -for x in t: pass # E: Need type annotation for variable +for x in t: pass [builtins fixtures/for.pyi] [case testForLoopOverNoneValuedTuple] import typing t = () -for x in None, None: pass # E: Need type annotation for variable +for x in None, None: pass [builtins fixtures/for.pyi] [case testForLoopOverTupleAndSubtyping] diff --git a/test-data/unit/check-typeddict.test b/test-data/unit/check-typeddict.test index 20e6bf63aee0f..78fade8c8258a 100644 --- a/test-data/unit/check-typeddict.test +++ b/test-data/unit/check-typeddict.test @@ -25,7 +25,7 @@ reveal_type(p) # E: Revealed type is 'TypedDict(x=builtins.int, y=builtins.int, from mypy_extensions import TypedDict EmptyDict = TypedDict('EmptyDict', {}) p = EmptyDict() -reveal_type(p) # E: Revealed type is 'TypedDict(_fallback=typing.Mapping[builtins.str, builtins.None])' +reveal_type(p) # E: Revealed type is 'TypedDict(_fallback=typing.Mapping[builtins.str, ])' [builtins fixtures/dict.pyi] @@ -112,7 +112,7 @@ class EmptyDict(TypedDict): pass p = EmptyDict() -reveal_type(p) # E: Revealed type is 'TypedDict(_fallback=typing.Mapping[builtins.str, builtins.None])' +reveal_type(p) # E: Revealed type is 'TypedDict(_fallback=typing.Mapping[builtins.str, ])' [builtins fixtures/dict.pyi] @@ -355,7 +355,7 @@ d2 = Cell(value='pear tree') joined_dicts = [d1, d2] reveal_type(d1) # E: Revealed type is 'TypedDict(x=builtins.int, y=builtins.int, _fallback=typing.Mapping[builtins.str, builtins.int])' reveal_type(d2) # E: Revealed type is 'TypedDict(value=builtins.str, _fallback=typing.Mapping[builtins.str, builtins.str])' -reveal_type(joined_dicts) # E: Revealed type is 'builtins.list[TypedDict(_fallback=typing.Mapping[builtins.str, builtins.None])]' +reveal_type(joined_dicts) # E: Revealed type is 'builtins.list[TypedDict(_fallback=typing.Mapping[builtins.str, ])]' [builtins fixtures/dict.pyi] [case testJoinOfTypedDictWithCompatibleMappingIsMapping] diff --git a/test-data/unit/check-varargs.test b/test-data/unit/check-varargs.test index f52f850792e72..86ee1d832c258 100644 --- a/test-data/unit/check-varargs.test +++ b/test-data/unit/check-varargs.test @@ -531,8 +531,8 @@ a, aa = G().f(*[a]) # Fail aa, a = G().f(*[a]) # Fail ab, aa = G().f(*[a]) # Fail -ao, ao = G().f(*[a]) # E: Incompatible types in assignment (expression has type List[None], variable has type List[object]) -aa, aa = G().f(*[a]) # E: Incompatible types in assignment (expression has type List[None], variable has type List[A]) +ao, ao = G().f(*[a]) # E: Incompatible types in assignment (expression has type List[], variable has type List[object]) +aa, aa = G().f(*[a]) # E: Incompatible types in assignment (expression has type List[], variable has type List[A]) class G(Generic[T]): def f(self, *a: S) -> Tuple[List[S], List[T]]: @@ -543,9 +543,9 @@ class B: pass [builtins fixtures/list.pyi] [out] main:9: error: Incompatible types in assignment (expression has type List[A], variable has type "A") -main:9: error: Incompatible types in assignment (expression has type List[None], variable has type List[A]) -main:10: error: Incompatible types in assignment (expression has type List[None], variable has type "A") -main:11: error: Incompatible types in assignment (expression has type List[None], variable has type List[A]) +main:9: error: Incompatible types in assignment (expression has type List[], variable has type List[A]) +main:10: error: Incompatible types in assignment (expression has type List[], variable has type "A") +main:11: error: Incompatible types in assignment (expression has type List[], variable has type List[A]) main:11: error: Argument 1 to "f" of "G" has incompatible type *List[A]; expected "B" diff --git a/test-data/unit/pythoneval.test b/test-data/unit/pythoneval.test index dfe021afa93ba..f8520bfdf15e2 100644 --- a/test-data/unit/pythoneval.test +++ b/test-data/unit/pythoneval.test @@ -1097,7 +1097,7 @@ MyDDict(dict)[0] _program.py:6: error: Argument 1 to "defaultdict" has incompatible type List[_T]; expected Callable[[], str] _program.py:9: error: Invalid index type "str" for "dict"; expected type "int" _program.py:9: error: Incompatible types in assignment (expression has type "int", target has type "str") -_program.py:19: error: List item 0 has incompatible type "Tuple[str, List[None]]" +_program.py:19: error: List item 0 has incompatible type "Tuple[str, List[]]" _program.py:23: error: Invalid index type "str" for "dict"; expected type "int" [case testNoSubcriptionOfStdlibCollections] diff --git a/test-data/unit/typexport-basic.test b/test-data/unit/typexport-basic.test index 2440fe75ca2f7..303c475cc3a3d 100644 --- a/test-data/unit/typexport-basic.test +++ b/test-data/unit/typexport-basic.test @@ -414,7 +414,7 @@ class B(A[C]): def g(self, c: C) -> None: self.f(c) [out] -CallExpr(8) : void +CallExpr(8) : builtins.None MemberExpr(8) : def (a: C) NameExpr(8) : C NameExpr(8) : B @@ -430,7 +430,7 @@ class B(A[C, T], Generic[T]): def g(self, c: C) -> None: self.f(c) [out] -CallExpr(9) : void +CallExpr(9) : builtins.None MemberExpr(9) : def (a: C) NameExpr(9) : C NameExpr(9) : B[T`1] @@ -446,7 +446,7 @@ b = None # type: B c = None # type: C b.f(c) [out] -CallExpr(9) : void +CallExpr(9) : builtins.None MemberExpr(9) : def (a: C) NameExpr(9) : B NameExpr(9) : C @@ -597,11 +597,11 @@ class A(Generic[T]): pass class B: pass class C(B): pass [out] -CallExpr(4) : void +CallExpr(4) : builtins.None CallExpr(4) : A[B] -CallExpr(5) : void +CallExpr(5) : builtins.None CallExpr(5) : A[B] -CallExpr(6) : void +CallExpr(6) : builtins.None CallExpr(6) : A[B] [case testInferGenericTypeForLocalVariable] @@ -1104,7 +1104,7 @@ m(fun, [out] IntExpr(13) : builtins.int ListExpr(13) : builtins.list[builtins.int] -CallExpr(14) : void +CallExpr(14) : builtins.None NameExpr(14) : def (s: builtins.int) -> builtins.int NameExpr(14) : def (fun: def (builtins.int) -> builtins.int, iter: builtins.list[builtins.int]) NameExpr(15) : builtins.list[builtins.int]