1515
1616using System ;
1717using System . Collections . Generic ;
18+ using System . Diagnostics ;
1819using System . Linq ;
1920using Microsoft . Python . Analysis . Analyzer . Evaluation ;
2021using Microsoft . Python . Analysis . Documents ;
@@ -75,10 +76,12 @@ internal void AddReturnValue(IMember value) {
7576 if ( value . IsUnknown ( ) ) {
7677 return ; // Don't add useless values.
7778 }
79+
7880 if ( StaticReturnValue . IsUnknown ( ) ) {
7981 SetReturnValue ( value , false ) ;
8082 return ;
8183 }
84+
8285 // If return value is set from annotation, it should not be changing.
8386 var currentType = StaticReturnValue . GetPythonType ( ) ;
8487 var valueType = value . GetPythonType ( ) ;
@@ -98,6 +101,7 @@ internal void SetReturnValueProvider(ReturnValueProvider provider)
98101 => _returnValueProvider = provider ;
99102
100103 #region IPythonFunctionOverload
104+
101105 public FunctionDefinition FunctionDefinition { get ; }
102106 public IPythonClassMember ClassMember { get ; }
103107 public string Name { get ; }
@@ -113,38 +117,11 @@ public string Documentation {
113117 }
114118
115119 public string GetReturnDocumentation ( IPythonType self = null ) {
116- if ( self == null ) {
117- return _returnDocumentation ;
118- }
119- var returnType = StaticReturnValue . GetPythonType ( ) ;
120- switch ( returnType ) {
121- case PythonClassType cls when cls . IsGeneric ( ) : {
122- // -> A[_T1, _T2, ...]
123- // Match arguments
124- var typeArgs = cls . GenericParameters . Keys
125- . Select ( n => cls . GenericParameters . TryGetValue ( n , out var t ) ? t : null )
126- . ExcludeDefault ( )
127- . ToArray ( ) ;
128- var specificReturnValue = cls . CreateSpecificType ( new ArgumentSet ( typeArgs ) ) ;
129- return specificReturnValue . Name ;
130- }
131- case IGenericTypeDefinition gtp1 when self is IPythonClassType cls : {
132- // -> _T
133- if ( cls . GenericParameters . TryGetValue ( gtp1 . Name , out var specificType ) ) {
134- return specificType . Name ;
135- }
136- // Try returning the constraint
137- // TODO: improve this, the heuristic is pretty basic and tailored to simple func(_T) -> _T
138- var name = StaticReturnValue . GetPythonType ( ) ? . Name ;
139- var typeDefVar = DeclaringModule . Analysis . GlobalScope . Variables [ name ] ;
140- if ( typeDefVar ? . Value is IGenericTypeDefinition gtp2 ) {
141- var t = gtp2 . Constraints . FirstOrDefault ( ) ;
142- if ( t != null ) {
143- return t . Name ;
144- }
145- }
146- break ;
147- }
120+ if ( self != null ) {
121+ var returnType = GetSpecificReturnType ( self as IPythonClassType , null ) ;
122+ if ( ! returnType . IsUnknown ( ) ) {
123+ return returnType . GetPythonType ( ) . Name ;
124+ }
148125 }
149126 return _returnDocumentation ;
150127 }
@@ -161,59 +138,72 @@ public IMember Call(IArgumentSet args, IPythonType self, Node callLocation = nul
161138 }
162139 }
163140
164- // If function returns generic, determine actual type based on the passed in specific type (self).
165- // If there is no self and no declaring type, the function is standalone.
166- if ( self == null && StaticReturnValue . IsGeneric ( ) && Parameters . Any ( p => p . IsGeneric ) ) {
167- return null ; // Evaluate standalone generic with arguments instead.
168- }
169- if ( ! ( self is IPythonClassType selfClassType ) ) {
170- return StaticReturnValue ;
171- }
141+ return GetSpecificReturnType ( self as IPythonClassType , args ) ;
142+ }
143+
144+ #endregion
172145
173- var returnType = StaticReturnValue . GetPythonType ( ) ;
174- switch ( returnType ) {
146+ private IMember GetSpecificReturnType ( IPythonClassType selfClassType , IArgumentSet args ) {
147+ var returnValueType = StaticReturnValue . GetPythonType ( ) ;
148+ switch ( returnValueType ) {
175149 case PythonClassType cls when cls . IsGeneric ( ) :
176- // -> A[_T1, _T2, ...]
177- // Match arguments
178- IReadOnlyList < IPythonType > typeArgs = null ;
179- var classGenericParameters = selfClassType . GenericParameters . Keys . ToArray ( ) ;
180- if ( classGenericParameters . Length > 0 ) {
181- // Declaring class is specific and provides definitions of generic parameters
182- typeArgs = classGenericParameters
183- . Select ( n => selfClassType . GenericParameters . TryGetValue ( n , out var t ) ? t : null )
184- . ExcludeDefault ( )
185- . ToArray ( ) ;
186- } else {
187- typeArgs = ExpressionEval . GetTypeArgumentsFromParameters ( this , args ) ;
188- }
189-
190- if ( typeArgs != null ) {
191- var specificReturnValue = cls . CreateSpecificType ( new ArgumentSet ( typeArgs ) ) ;
192- return new PythonInstance ( specificReturnValue ) ;
193- }
194- break ;
195-
196- case IGenericTypeDefinition gtp1 : {
197- // -> _T
198- if ( selfClassType . GenericParameters . TryGetValue ( gtp1 . Name , out var specificType ) ) {
199- return new PythonInstance ( specificType ) ;
200- }
201- // Try returning the constraint
202- // TODO: improve this, the heuristic is pretty basic and tailored to simple func(_T) -> _T
203- var name = StaticReturnValue . GetPythonType ( ) ? . Name ;
204- var typeDefVar = DeclaringModule . Analysis . GlobalScope . Variables [ name ] ;
205- if ( typeDefVar ? . Value is IGenericTypeDefinition gtp2 ) {
206- // See if the instance (self) type satisfies one of the constraints.
207- return selfClassType . Mro . Any ( b => gtp2 . Constraints . Any ( c => c . Equals ( b ) ) )
208- ? selfClassType
209- : gtp2 . Constraints . FirstOrDefault ( ) ;
210- }
211-
212- break ;
213- }
150+ return CreateSpecificReturnFromClassType ( selfClassType , cls , args ) ; // -> A[_T1, _T2, ...]
151+
152+ case IGenericTypeDefinition gtd1 when selfClassType != null :
153+ return CreateSpecificReturnFromTypeVar ( selfClassType , gtd1 ) ; // -> _T
154+
155+ case IGenericTypeDefinition gtd2 when args != null : // -> T on standalone function.
156+ return args . Arguments . FirstOrDefault ( a => gtd2 . Equals ( a . Type ) ) ? . Value as IMember ;
157+
158+ case IGenericType gt when args != null : // -> CLASS[T] on standalone function (i.e. -> List[T]).
159+ var typeArgs = ExpressionEval . GetTypeArgumentsFromParameters ( this , args ) ;
160+ Debug . Assert ( typeArgs != null ) ;
161+ return gt . CreateSpecificType ( typeArgs ) ;
214162 }
163+
215164 return StaticReturnValue ;
216165 }
217- #endregion
166+
167+ private IMember CreateSpecificReturnFromClassType ( IPythonClassType selfClassType , PythonClassType returnClassType , IArgumentSet args ) {
168+ // -> A[_T1, _T2, ...]
169+ // Match arguments
170+ IReadOnlyList < IPythonType > typeArgs = null ;
171+ var classGenericParameters = selfClassType ? . GenericParameters . Keys . ToArray ( ) ?? Array . Empty < string > ( ) ;
172+ if ( classGenericParameters . Length > 0 && selfClassType != null ) {
173+ // Declaring class is specific and provides definitions of generic parameters
174+ typeArgs = classGenericParameters
175+ . Select ( n => selfClassType . GenericParameters . TryGetValue ( n , out var t ) ? t : null )
176+ . ExcludeDefault ( )
177+ . ToArray ( ) ;
178+ } else if ( args != null ) {
179+ typeArgs = ExpressionEval . GetTypeArgumentsFromParameters ( this , args ) ;
180+ }
181+
182+ if ( typeArgs != null ) {
183+ var specificReturnValue = returnClassType . CreateSpecificType ( new ArgumentSet ( typeArgs ) ) ;
184+ return new PythonInstance ( specificReturnValue ) ;
185+ }
186+
187+ return null ;
188+ }
189+
190+ private IMember CreateSpecificReturnFromTypeVar ( IPythonClassType selfClassType , IGenericTypeDefinition returnType ) {
191+ if ( selfClassType . GenericParameters . TryGetValue ( returnType . Name , out var specificType ) ) {
192+ return new PythonInstance ( specificType ) ;
193+ }
194+
195+ // Try returning the constraint
196+ // TODO: improve this, the heuristic is pretty basic and tailored to simple func(_T) -> _T
197+ var name = StaticReturnValue . GetPythonType ( ) ? . Name ;
198+ var typeDefVar = DeclaringModule . Analysis . GlobalScope . Variables [ name ] ;
199+ if ( typeDefVar ? . Value is IGenericTypeDefinition gtp2 ) {
200+ // See if the instance (self) type satisfies one of the constraints.
201+ return selfClassType . Mro . Any ( b => gtp2 . Constraints . Any ( c => c . Equals ( b ) ) )
202+ ? selfClassType
203+ : gtp2 . Constraints . FirstOrDefault ( ) ;
204+ }
205+
206+ return null ;
207+ }
218208 }
219209}
0 commit comments