@@ -44,6 +44,11 @@ interface EnumClassInfo {
44
44
valueType : Type ;
45
45
}
46
46
47
+ interface AliasMapEntry {
48
+ alias : string ;
49
+ module : 'builtins' | 'collections' ;
50
+ }
51
+
47
52
// At some point, we'll cut off the analysis passes and assume
48
53
// we're making no forward progress. This should happen only
49
54
// on the case of bugs in the analyzer.
@@ -780,16 +785,44 @@ export class TypeAnalyzer extends ParseTreeWalker {
780
785
'NoReturn' , 'Union' , 'Optional' , 'List' , 'Dict' , 'DefaultDict' ,
781
786
'Set' , 'FrozenSet' , 'Deque' , 'ChainMap' ] ;
782
787
if ( specialTypes . find ( t => t === assignedName ) ) {
788
+ const aliasMap : { [ name : string ] : AliasMapEntry } = {
789
+ 'List' : { alias : 'list' , module : 'builtins' } ,
790
+ 'Dict' : { alias : 'dict' , module : 'builtins' } ,
791
+ 'DefaultDict' : { alias : 'defaultdict' , module : 'collections' } ,
792
+ 'Set' : { alias : 'set' , module : 'builtins' } ,
793
+ 'FrozenSet' : { alias : 'frozenset' , module : 'builtins' } ,
794
+ 'Deque' : { alias : 'deque' , module : 'collections' } ,
795
+ 'ChainMap' : { alias : 'ChainMap' , module : 'collections' }
796
+ } ;
797
+
783
798
// Synthesize a class.
784
799
let specialClassType = new ClassType ( assignedName ,
785
800
ClassTypeFlags . BuiltInClass | ClassTypeFlags . SpecialBuiltIn ,
786
801
DefaultTypeSourceId ) ;
787
802
788
- let aliasClass = ScopeUtils . getBuiltInType ( this . _currentScope ,
789
- assignedName . toLowerCase ( ) ) ;
790
- if ( aliasClass instanceof ClassType ) {
791
- specialClassType . addBaseClass ( aliasClass , false ) ;
792
- specialClassType . setAliasClass ( aliasClass ) ;
803
+ // See if we need to locate an alias class to bind it to.
804
+ const aliasMapEntry = aliasMap [ assignedName ] ;
805
+ if ( aliasMapEntry ) {
806
+ let aliasClass : Type | undefined ;
807
+ const aliasName = aliasMapEntry . alias ;
808
+
809
+ if ( aliasMapEntry . module === 'builtins' ) {
810
+ aliasClass = ScopeUtils . getBuiltInType ( this . _currentScope , aliasName ) ;
811
+ } else if ( aliasMapEntry . module === 'collections' ) {
812
+ // The typing.pyi file imports collections.
813
+ let collectionsScope = this . _findCollectionsImportScope ( ) ;
814
+ if ( collectionsScope ) {
815
+ const symbolInfo = collectionsScope . lookUpSymbol ( aliasName ) ;
816
+ if ( symbolInfo ) {
817
+ aliasClass = symbolInfo . currentType ;
818
+ }
819
+ }
820
+ }
821
+
822
+ if ( aliasClass instanceof ClassType ) {
823
+ specialClassType . addBaseClass ( aliasClass , false ) ;
824
+ specialClassType . setAliasClass ( aliasClass ) ;
825
+ }
793
826
}
794
827
795
828
specialType = specialClassType ;
@@ -823,6 +856,19 @@ export class TypeAnalyzer extends ParseTreeWalker {
823
856
return false ;
824
857
}
825
858
859
+ private _findCollectionsImportScope ( ) {
860
+ let collectionResults = Object . keys ( this . _fileInfo . importMap ) . find ( path => {
861
+ return path . endsWith ( 'collections/__init__.pyi' ) ;
862
+ } ) ;
863
+
864
+ if ( collectionResults ) {
865
+ const moduleNode = this . _fileInfo . importMap [ collectionResults ] . parseTree ;
866
+ return AnalyzerNodeInfo . getScope ( moduleNode ) ;
867
+ }
868
+
869
+ return undefined ;
870
+ }
871
+
826
872
visitName ( node : NameNode ) {
827
873
let symbolInScope = this . _currentScope . lookUpSymbolRecursive ( node . nameToken . value ) ;
828
874
0 commit comments