@@ -28,7 +28,7 @@ use crate::symbol::{Boundness, Symbol};
28
28
use crate :: types:: diagnostic:: TypeCheckDiagnosticsBuilder ;
29
29
use crate :: types:: mro:: { ClassBase , Mro , MroError , MroIterator } ;
30
30
use crate :: types:: narrow:: narrowing_constraint;
31
- use crate :: { Db , FxOrderSet , Module , Program } ;
31
+ use crate :: { Db , FxOrderSet , Module , Program , PythonVersion } ;
32
32
33
33
mod builder;
34
34
mod diagnostic;
@@ -1897,13 +1897,13 @@ impl<'db> KnownClass {
1897
1897
}
1898
1898
1899
1899
pub fn to_class_literal ( self , db : & ' db dyn Db ) -> Type < ' db > {
1900
- core_module_symbol ( db, self . canonical_module ( ) , self . as_str ( ) )
1900
+ core_module_symbol ( db, self . canonical_module ( db ) , self . as_str ( ) )
1901
1901
. ignore_possibly_unbound ( )
1902
1902
. unwrap_or ( Type :: Unknown )
1903
1903
}
1904
1904
1905
1905
/// Return the module in which we should look up the definition for this class
1906
- pub ( crate ) const fn canonical_module ( self ) -> CoreStdlibModule {
1906
+ pub ( crate ) fn canonical_module ( self , db : & ' db dyn Db ) -> CoreStdlibModule {
1907
1907
match self {
1908
1908
Self :: Bool
1909
1909
| Self :: Object
@@ -1921,10 +1921,18 @@ impl<'db> KnownClass {
1921
1921
Self :: GenericAlias | Self :: ModuleType | Self :: FunctionType => CoreStdlibModule :: Types ,
1922
1922
Self :: NoneType => CoreStdlibModule :: Typeshed ,
1923
1923
Self :: SpecialForm | Self :: TypeVar | Self :: TypeAliasType => CoreStdlibModule :: Typing ,
1924
- // TODO when we understand sys.version_info, we will need an explicit fallback here,
1925
- // because typing_extensions has a 3.13+ re-export for the `typing.NoDefault`
1926
- // singleton, but not for `typing._NoDefaultType`
1927
- Self :: NoDefaultType => CoreStdlibModule :: TypingExtensions ,
1924
+ Self :: NoDefaultType => {
1925
+ let python_version = Program :: get ( db) . target_version ( db) ;
1926
+
1927
+ // typing_extensions has a 3.13+ re-export for the `typing.NoDefault`
1928
+ // singleton, but not for `typing._NoDefaultType`. So we need to switch
1929
+ // to `typing._NoDefaultType` for newer versions:
1930
+ if python_version >= PythonVersion :: PY313 {
1931
+ CoreStdlibModule :: Typing
1932
+ } else {
1933
+ CoreStdlibModule :: TypingExtensions
1934
+ }
1935
+ }
1928
1936
}
1929
1937
}
1930
1938
@@ -1984,11 +1992,11 @@ impl<'db> KnownClass {
1984
1992
} ;
1985
1993
1986
1994
let module = file_to_module ( db, file) ?;
1987
- candidate. check_module ( & module) . then_some ( candidate)
1995
+ candidate. check_module ( db , & module) . then_some ( candidate)
1988
1996
}
1989
1997
1990
1998
/// Return `true` if the module of `self` matches `module_name`
1991
- fn check_module ( self , module : & Module ) -> bool {
1999
+ fn check_module ( self , db : & ' db dyn Db , module : & Module ) -> bool {
1992
2000
if !module. search_path ( ) . is_standard_library ( ) {
1993
2001
return false ;
1994
2002
}
@@ -2008,7 +2016,7 @@ impl<'db> KnownClass {
2008
2016
| Self :: GenericAlias
2009
2017
| Self :: ModuleType
2010
2018
| Self :: VersionInfo
2011
- | Self :: FunctionType => module. name ( ) == self . canonical_module ( ) . as_str ( ) ,
2019
+ | Self :: FunctionType => module. name ( ) == self . canonical_module ( db ) . as_str ( ) ,
2012
2020
Self :: NoneType => matches ! ( module. name( ) . as_str( ) , "_typeshed" | "types" ) ,
2013
2021
Self :: SpecialForm | Self :: TypeVar | Self :: TypeAliasType | Self :: NoDefaultType => {
2014
2022
matches ! ( module. name( ) . as_str( ) , "typing" | "typing_extensions" )
@@ -3683,13 +3691,28 @@ pub(crate) mod tests {
3683
3691
#[ test_case( Ty :: None ) ]
3684
3692
#[ test_case( Ty :: BooleanLiteral ( true ) ) ]
3685
3693
#[ test_case( Ty :: BooleanLiteral ( false ) ) ]
3686
- #[ test_case( Ty :: KnownClassInstance ( KnownClass :: NoDefaultType ) ) ]
3687
3694
fn is_singleton ( from : Ty ) {
3688
3695
let db = setup_db ( ) ;
3689
3696
3690
3697
assert ! ( from. into_type( & db) . is_singleton( & db) ) ;
3691
3698
}
3692
3699
3700
+ /// Explicitly test for Python version <3.13 and >=3.13, to ensure that
3701
+ /// the fallback to `typing_extensions` is working correctly.
3702
+ /// See [`KnownClass::canonical_module`] for more information.
3703
+ #[ test_case( PythonVersion :: PY312 ) ]
3704
+ #[ test_case( PythonVersion :: PY313 ) ]
3705
+ fn no_default_type_is_singleton ( python_version : PythonVersion ) {
3706
+ let db = TestDbBuilder :: new ( )
3707
+ . with_python_version ( python_version)
3708
+ . build ( )
3709
+ . unwrap ( ) ;
3710
+
3711
+ let no_default = Ty :: KnownClassInstance ( KnownClass :: NoDefaultType ) . into_type ( & db) ;
3712
+
3713
+ assert ! ( no_default. is_singleton( & db) ) ;
3714
+ }
3715
+
3693
3716
#[ test_case( Ty :: None ) ]
3694
3717
#[ test_case( Ty :: BooleanLiteral ( true ) ) ]
3695
3718
#[ test_case( Ty :: IntLiteral ( 1 ) ) ]
0 commit comments