@@ -682,24 +682,32 @@ def analyze_unbound_type_without_type_info(
682
682
# a "Literal[...]" type. So, if `defining_literal` is not set,
683
683
# we bail out early with an error.
684
684
#
685
- # If, in the distant future, we decide to permit things like
686
- # `def foo(x: Color.RED) -> None: ...`, we can remove that
687
- # check entirely.
685
+ # Based: we permit things like `def foo(x: Color.RED) -> None: ...`
688
686
if isinstance (sym .node , Var ) and sym .node .info and sym .node .info .is_enum :
689
687
value = sym .node .name
690
- base_enum_short_name = sym . node . info . name
688
+ # it's invalid to use in an expression, ie: a TypeAlias
691
689
if not defining_literal :
692
- msg = message_registry .INVALID_TYPE_RAW_ENUM_VALUE .format (
693
- base_enum_short_name , value
694
- )
695
- self .fail (msg , t )
696
- return AnyType (TypeOfAny .from_error )
697
- return LiteralType (
690
+ if not self .options .bare_literals :
691
+ base_enum_short_name = sym .node .info .name
692
+ msg = message_registry .INVALID_TYPE_RAW_ENUM_VALUE .format (
693
+ base_enum_short_name , value
694
+ )
695
+ self .fail (msg , t )
696
+ if t .expression :
697
+ base_enum_short_name = sym .node .info .name
698
+ name = f"{ base_enum_short_name } .{ value } "
699
+ msg = message_registry .INVALID_BARE_LITERAL .format (name )
700
+ self .fail (msg , t )
701
+ result = LiteralType (
698
702
value = value ,
699
703
fallback = Instance (sym .node .info , [], line = t .line , column = t .column ),
700
704
line = t .line ,
701
705
column = t .column ,
706
+ bare_literal = True ,
702
707
)
708
+ if t .expression :
709
+ return result
710
+ return result .accept (self )
703
711
704
712
# None of the above options worked. We parse the args (if there are any)
705
713
# to make sure there are no remaining semanal-only types, then give up.
@@ -934,16 +942,18 @@ def visit_raw_expression_type(self, t: RawExpressionType) -> Type:
934
942
# "fake literals" should always be wrapped in an UnboundType
935
943
# corresponding to 'Literal'.
936
944
#
937
- # Note: if at some point in the distant future, we decide to
938
- # make signatures like "foo(x: 20) -> None" legal, we can change
939
- # this method so it generates and returns an actual LiteralType
940
- # instead.
945
+ # Based: signatures like "foo(x: 20) -> None" are legal, this method
946
+ # generates and returns an actual LiteralType instead.
941
947
942
948
if self .report_invalid_types :
949
+ msg = None
943
950
if t .base_type_name in ("builtins.int" , "builtins.bool" ):
944
- # The only time it makes sense to use an int or bool is inside of
945
- # a literal type.
946
- msg = f"Invalid type: try using Literal[{ repr (t .literal_value )} ] instead?"
951
+ if not self .options .bare_literals :
952
+ # The only time it makes sense to use an int or bool is inside of
953
+ # a literal type.
954
+ msg = f"Invalid type: try using Literal[{ repr (t .literal_value )} ] instead?"
955
+ if t .expression :
956
+ msg = message_registry .INVALID_BARE_LITERAL .format (t .literal_value )
947
957
elif t .base_type_name in ("builtins.float" , "builtins.complex" ):
948
958
# We special-case warnings for floats and complex numbers.
949
959
msg = f"Invalid type: { t .simple_name ()} literals cannot be used as a type"
@@ -954,14 +964,38 @@ def visit_raw_expression_type(self, t: RawExpressionType) -> Type:
954
964
# string, it's unclear if the user meant to construct a literal type
955
965
# or just misspelled a regular type. So we avoid guessing.
956
966
msg = "Invalid type comment or annotation"
957
-
958
- self .fail (msg , t , code = codes .VALID_TYPE )
959
- if t .note is not None :
960
- self .note (t .note , t , code = codes .VALID_TYPE )
961
-
967
+ if msg :
968
+ self .fail (msg , t , code = codes .VALID_TYPE )
969
+ if t .note is not None :
970
+ self .note (t .note , t , code = codes .VALID_TYPE )
971
+ if t .base_type_name in ("builtins.int" , "builtins.bool" ):
972
+ v = t .literal_value
973
+ assert v is not None
974
+ result = LiteralType (
975
+ v ,
976
+ fallback = self .named_type (t .base_type_name ),
977
+ line = t .line ,
978
+ column = t .column ,
979
+ bare_literal = True ,
980
+ )
981
+ if t .expression :
982
+ return result
983
+ return result .accept (self )
962
984
return AnyType (TypeOfAny .from_error , line = t .line , column = t .column )
963
985
964
986
def visit_literal_type (self , t : LiteralType ) -> Type :
987
+ if (
988
+ self .nesting_level
989
+ and t .bare_literal
990
+ and not (self .api .is_future_flag_set ("annotations" ) or self .api .is_stub_file )
991
+ and self .options .bare_literals
992
+ ):
993
+ self .fail (
994
+ f'"{ t } " is a bare literal and shouldn\' t be used in a type operation without'
995
+ ' "__future__.annotations"' ,
996
+ t ,
997
+ code = codes .VALID_TYPE ,
998
+ )
965
999
return t
966
1000
967
1001
def visit_star_type (self , t : StarType ) -> Type :
0 commit comments