Skip to content

Commit

Permalink
Add LiteralType and stub methods to type visitors (#5934)
Browse files Browse the repository at this point in the history
This diff adds a 'LiteralType' class to types.py and adds a
corresponding stub method to all of the type visitors.

Most of these stub methods just throw a 'NotImplementedError',
though I did pencil in a few implementations that looked obvious.

The reason I'm doing this now instead of later is because I want
to start by getting these kind of big, gross, multi-file changes
out of the way early and try and have any subsequent pull requests
be more focused.

I also want to formally confirm that the correct approach here
*is* to create a new 'LiteralType' class before I start on the
rest of the implementation work. (Other possible approaches would
be to tack on some extra attribute to 'Instance', or make
'LiteralType' a subclass of 'Instance'.)

No tests, sorry. My plan is to work on modifying the parsing
and semantic analysis steps next before returning back to these
the unimplemented methods and add tests then --  here's the
tracking issue for these TODOs:
#5935

Tests shouldn't be necessary, in any case: everything I added
just now is basically dead code.
  • Loading branch information
Michael0x2a authored Nov 22, 2018
1 parent 1428513 commit b099496
Show file tree
Hide file tree
Showing 15 changed files with 153 additions and 14 deletions.
5 changes: 4 additions & 1 deletion mypy/constraints.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
from mypy.types import (
CallableType, Type, TypeVisitor, UnboundType, AnyType, NoneTyp, TypeVarType, Instance,
TupleType, TypedDictType, UnionType, Overloaded, ErasedType, PartialType, DeletedType,
UninhabitedType, TypeType, TypeVarId, TypeQuery, is_named_instance, TypeOfAny
UninhabitedType, TypeType, TypeVarId, TypeQuery, is_named_instance, TypeOfAny, LiteralType,
)
from mypy.maptype import map_instance_to_supertype
from mypy import nodes
Expand Down Expand Up @@ -473,6 +473,9 @@ def visit_typeddict_type(self, template: TypedDictType) -> List[Constraint]:
else:
return []

def visit_literal_type(self, template: LiteralType) -> List[Constraint]:
raise NotImplementedError()

def visit_union_type(self, template: UnionType) -> List[Constraint]:
assert False, ("Unexpected UnionType in ConstraintBuilderVisitor"
" (should have been handled in infer_constraints)")
Expand Down
8 changes: 7 additions & 1 deletion mypy/erasetype.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
from mypy.types import (
Type, TypeVisitor, UnboundType, AnyType, NoneTyp, TypeVarId, Instance, TypeVarType,
CallableType, TupleType, TypedDictType, UnionType, Overloaded, ErasedType, PartialType,
DeletedType, TypeTranslator, UninhabitedType, TypeType, TypeOfAny
DeletedType, TypeTranslator, UninhabitedType, TypeType, TypeOfAny, LiteralType,
)
from mypy.nodes import ARG_STAR, ARG_STAR2

Expand Down Expand Up @@ -78,6 +78,12 @@ def visit_tuple_type(self, t: TupleType) -> Type:
def visit_typeddict_type(self, t: TypedDictType) -> Type:
return t.fallback.accept(self)

def visit_literal_type(self, t: LiteralType) -> Type:
# The fallback for literal types should always be either
# something like int or str, or an enum class -- types that
# don't contain any TypeVars. So there's no need to visit it.
return t

def visit_union_type(self, t: UnionType) -> Type:
erased_items = [erase_type(item) for item in t.items]
return UnionType.make_simplified_union(erased_items)
Expand Down
6 changes: 5 additions & 1 deletion mypy/expandtype.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
Type, Instance, CallableType, TypeVisitor, UnboundType, AnyType,
NoneTyp, TypeVarType, Overloaded, TupleType, TypedDictType, UnionType,
ErasedType, PartialType, DeletedType, UninhabitedType, TypeType, TypeVarId,
FunctionLike, TypeVarDef
FunctionLike, TypeVarDef, LiteralType,
)


Expand Down Expand Up @@ -111,6 +111,10 @@ def visit_tuple_type(self, t: TupleType) -> Type:
def visit_typeddict_type(self, t: TypedDictType) -> Type:
return t.copy_modified(item_types=self.expand_types(t.items.values()))

def visit_literal_type(self, t: LiteralType) -> Type:
# TODO: Verify this implementation is correct
return t

def visit_union_type(self, t: UnionType) -> Type:
# After substituting for type variables in t.items,
# some of the resulting types might be subtypes of others.
Expand Down
5 changes: 4 additions & 1 deletion mypy/fixup.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
)
from mypy.types import (
CallableType, Instance, Overloaded, TupleType, TypedDictType,
TypeVarType, UnboundType, UnionType, TypeVisitor,
TypeVarType, UnboundType, UnionType, TypeVisitor, LiteralType,
TypeType, NOT_READY
)
from mypy.visitor import NodeVisitor
Expand Down Expand Up @@ -206,6 +206,9 @@ def visit_typeddict_type(self, tdt: TypedDictType) -> None:
if tdt.fallback is not None:
tdt.fallback.accept(self)

def visit_literal_type(self, lt: LiteralType) -> None:
lt.fallback.accept(self)

def visit_type_var(self, tvt: TypeVarType) -> None:
if tvt.values:
for vt in tvt.values:
Expand Down
3 changes: 3 additions & 0 deletions mypy/indirection.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,9 @@ def visit_tuple_type(self, t: types.TupleType) -> Set[str]:
def visit_typeddict_type(self, t: types.TypedDictType) -> Set[str]:
return self._visit(t.items.values()) | self._visit(t.fallback)

def visit_literal_type(self, t: types.LiteralType) -> Set[str]:
return self._visit(t.fallback)

def visit_star_type(self, t: types.StarType) -> Set[str]:
return set()

Expand Down
7 changes: 5 additions & 2 deletions mypy/join.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@

from mypy.types import (
Type, AnyType, NoneTyp, TypeVisitor, Instance, UnboundType, TypeVarType, CallableType,
TupleType, TypedDictType, ErasedType, UnionType, FunctionLike, Overloaded,
PartialType, DeletedType, UninhabitedType, TypeType, true_or_false, TypeOfAny
TupleType, TypedDictType, ErasedType, UnionType, FunctionLike, Overloaded, LiteralType,
PartialType, DeletedType, UninhabitedType, TypeType, true_or_false, TypeOfAny,
)
from mypy.maptype import map_instance_to_supertype
from mypy.subtypes import (
Expand Down Expand Up @@ -267,6 +267,9 @@ def visit_typeddict_type(self, t: TypedDictType) -> Type:
else:
return self.default(self.s)

def visit_literal_type(self, t: LiteralType) -> Type:
raise NotImplementedError()

def visit_partial_type(self, t: PartialType) -> Type:
# We only have partial information so we can't decide the join result. We should
# never get here.
Expand Down
5 changes: 4 additions & 1 deletion mypy/meet.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
from mypy.types import (
Type, AnyType, TypeVisitor, UnboundType, NoneTyp, TypeVarType, Instance, CallableType,
TupleType, TypedDictType, ErasedType, UnionType, PartialType, DeletedType,
UninhabitedType, TypeType, TypeOfAny, Overloaded, FunctionLike,
UninhabitedType, TypeType, TypeOfAny, Overloaded, FunctionLike, LiteralType,
)
from mypy.subtypes import (
is_equivalent, is_subtype, is_protocol_implementation, is_callable_compatible,
Expand Down Expand Up @@ -520,6 +520,9 @@ def visit_typeddict_type(self, t: TypedDictType) -> Type:
else:
return self.default(self.s)

def visit_literal_type(self, t: LiteralType) -> Type:
raise NotImplementedError()

def visit_partial_type(self, t: PartialType) -> Type:
# We can't determine the meet of partial types. We should never get here.
assert False, 'Internal error'
Expand Down
10 changes: 9 additions & 1 deletion mypy/sametypes.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
from mypy.types import (
Type, UnboundType, AnyType, NoneTyp, TupleType, TypedDictType,
UnionType, CallableType, TypeVarType, Instance, TypeVisitor, ErasedType,
Overloaded, PartialType, DeletedType, UninhabitedType, TypeType
Overloaded, PartialType, DeletedType, UninhabitedType, TypeType, LiteralType,
)


Expand Down Expand Up @@ -114,6 +114,14 @@ def visit_typeddict_type(self, left: TypedDictType) -> bool:
else:
return False

def visit_literal_type(self, left: LiteralType) -> bool:
if isinstance(self.right, LiteralType):
if left.value != self.right.value:
return False
return is_same_type(left.fallback, self.right.fallback)
else:
return False

def visit_union_type(self, left: UnionType) -> bool:
if isinstance(self.right, UnionType):
# Check that everything in left is in right
Expand Down
5 changes: 4 additions & 1 deletion mypy/server/astdiff.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ class level -- these are handled at attribute level (say, 'mod.Cls.method'
from mypy.types import (
Type, TypeVisitor, UnboundType, AnyType, NoneTyp, UninhabitedType,
ErasedType, DeletedType, Instance, TypeVarType, CallableType, TupleType, TypedDictType,
UnionType, Overloaded, PartialType, TypeType
UnionType, Overloaded, PartialType, TypeType, LiteralType,
)
from mypy.util import get_prefix

Expand Down Expand Up @@ -315,6 +315,9 @@ def visit_typeddict_type(self, typ: TypedDictType) -> SnapshotItem:
required = tuple(sorted(typ.required_keys))
return ('TypedDictType', items, required)

def visit_literal_type(self, typ: LiteralType) -> SnapshotItem:
return ('LiteralType', typ.value, snapshot_type(typ.fallback))

def visit_union_type(self, typ: UnionType) -> SnapshotItem:
# Sort and remove duplicates so that we can use equality to test for
# equivalent union type snapshots.
Expand Down
5 changes: 4 additions & 1 deletion mypy/server/astmerge.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@
from mypy.types import (
Type, SyntheticTypeVisitor, Instance, AnyType, NoneTyp, CallableType, DeletedType, PartialType,
TupleType, TypeType, TypeVarType, TypedDictType, UnboundType, UninhabitedType, UnionType,
Overloaded, TypeVarDef, TypeList, CallableArgument, EllipsisType, StarType
Overloaded, TypeVarDef, TypeList, CallableArgument, EllipsisType, StarType, LiteralType,
)
from mypy.util import get_prefix, replace_object_state
from mypy.typestate import TypeState
Expand Down Expand Up @@ -391,6 +391,9 @@ def visit_typeddict_type(self, typ: TypedDictType) -> None:
value_type.accept(self)
typ.fallback.accept(self)

def visit_literal_type(self, typ: LiteralType) -> None:
typ.fallback.accept(self)

def visit_unbound_type(self, typ: UnboundType) -> None:
for arg in typ.args:
arg.accept(self)
Expand Down
5 changes: 4 additions & 1 deletion mypy/server/deps.py
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ class 'mod.Cls'. This can also refer to an attribute inherited from a
from mypy.types import (
Type, Instance, AnyType, NoneTyp, TypeVisitor, CallableType, DeletedType, PartialType,
TupleType, TypeType, TypeVarType, TypedDictType, UnboundType, UninhabitedType, UnionType,
FunctionLike, ForwardRef, Overloaded, TypeOfAny
FunctionLike, ForwardRef, Overloaded, TypeOfAny, LiteralType,
)
from mypy.server.trigger import make_trigger, make_wildcard_trigger
from mypy.util import correct_relative_import
Expand Down Expand Up @@ -949,6 +949,9 @@ def visit_typeddict_type(self, typ: TypedDictType) -> List[str]:
triggers.extend(self.get_type_triggers(typ.fallback))
return triggers

def visit_literal_type(self, typ: LiteralType) -> List[str]:
return self.get_type_triggers(typ.fallback)

def visit_unbound_type(self, typ: UnboundType) -> List[str]:
return []

Expand Down
8 changes: 7 additions & 1 deletion mypy/subtypes.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
Type, AnyType, UnboundType, TypeVisitor, FormalArgument, NoneTyp, function_type,
Instance, TypeVarType, CallableType, TupleType, TypedDictType, UnionType, Overloaded,
ErasedType, PartialType, DeletedType, UninhabitedType, TypeType, is_named_instance,
FunctionLike, TypeOfAny
FunctionLike, TypeOfAny, LiteralType,
)
import mypy.applytype
import mypy.constraints
Expand Down Expand Up @@ -327,6 +327,9 @@ def visit_typeddict_type(self, left: TypedDictType) -> bool:
else:
return False

def visit_literal_type(self, t: LiteralType) -> bool:
raise NotImplementedError()

def visit_overloaded(self, left: Overloaded) -> bool:
right = self.right
if isinstance(right, Instance):
Expand Down Expand Up @@ -1168,6 +1171,9 @@ def visit_typeddict_type(self, left: TypedDictType) -> bool:
return True
return self._is_proper_subtype(left.fallback, right)

def visit_literal_type(self, left: LiteralType) -> bool:
raise NotImplementedError()

def visit_overloaded(self, left: Overloaded) -> bool:
# TODO: What's the right thing to do here?
return False
Expand Down
19 changes: 18 additions & 1 deletion mypy/type_visitor.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
T = TypeVar('T')

from mypy.types import (
Type, AnyType, CallableType, FunctionLike, Overloaded, TupleType, TypedDictType,
Type, AnyType, CallableType, FunctionLike, Overloaded, TupleType, TypedDictType, LiteralType,
Instance, NoneTyp, TypeType, TypeOfAny,
UnionType, TypeVarId, TypeVarType, PartialType, DeletedType, UninhabitedType, TypeVarDef,
UnboundType, ErasedType, ForwardRef, StarType, EllipsisType, TypeList, CallableArgument,
Expand Down Expand Up @@ -85,6 +85,10 @@ def visit_tuple_type(self, t: TupleType) -> T:
def visit_typeddict_type(self, t: TypedDictType) -> T:
pass

@abstractmethod
def visit_literal_type(self, t: LiteralType) -> T:
pass

@abstractmethod
def visit_union_type(self, t: UnionType) -> T:
pass
Expand Down Expand Up @@ -181,6 +185,16 @@ def visit_typeddict_type(self, t: TypedDictType) -> Type:
cast(Any, t.fallback.accept(self)),
t.line, t.column)

def visit_literal_type(self, t: LiteralType) -> Type:
fallback = t.fallback.accept(self)
assert isinstance(fallback, Instance)
return LiteralType(
value=t.value,
fallback=fallback,
line=t.line,
column=t.column,
)

def visit_union_type(self, t: UnionType) -> Type:
return UnionType(self.translate_types(t.items), t.line, t.column)

Expand Down Expand Up @@ -264,6 +278,9 @@ def visit_tuple_type(self, t: TupleType) -> T:
def visit_typeddict_type(self, t: TypedDictType) -> T:
return self.query_types(t.items.values())

def visit_literal_type(self, t: LiteralType) -> T:
return self.strategy([])

def visit_star_type(self, t: StarType) -> T:
return t.type.accept(self)

Expand Down
9 changes: 8 additions & 1 deletion mypy/typeanal.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@
Type, UnboundType, TypeVarType, TupleType, TypedDictType, UnionType, Instance, AnyType,
CallableType, NoneTyp, DeletedType, TypeList, TypeVarDef, TypeVisitor, SyntheticTypeVisitor,
StarType, PartialType, EllipsisType, UninhabitedType, TypeType, get_typ_args, set_typ_args,
CallableArgument, get_type_vars, TypeQuery, union_items, TypeOfAny, ForwardRef, Overloaded
CallableArgument, get_type_vars, TypeQuery, union_items, TypeOfAny, ForwardRef, Overloaded,
LiteralType,
)

from mypy.nodes import (
Expand Down Expand Up @@ -459,6 +460,9 @@ def visit_typeddict_type(self, t: TypedDictType) -> Type:
])
return TypedDictType(items, set(t.required_keys), t.fallback)

def visit_literal_type(self, t: LiteralType) -> Type:
raise NotImplementedError()

def visit_star_type(self, t: StarType) -> Type:
return StarType(self.anal_type(t.type), t.line)

Expand Down Expand Up @@ -754,6 +758,9 @@ def visit_typeddict_type(self, t: TypedDictType) -> None:
for item_type in t.items.values():
item_type.accept(self)

def visit_literal_type(self, t: LiteralType) -> None:
raise NotImplementedError()

def visit_union_type(self, t: UnionType) -> None:
for item in t.items:
item.accept(self)
Expand Down
Loading

0 comments on commit b099496

Please sign in to comment.