15
15
16
16
using System ;
17
17
using System . Collections . Generic ;
18
+ using System . Diagnostics ;
18
19
using System . Linq ;
19
20
using Microsoft . Python . Analysis . Analyzer . Evaluation ;
20
21
using Microsoft . Python . Analysis . Documents ;
@@ -75,10 +76,12 @@ internal void AddReturnValue(IMember value) {
75
76
if ( value . IsUnknown ( ) ) {
76
77
return ; // Don't add useless values.
77
78
}
79
+
78
80
if ( StaticReturnValue . IsUnknown ( ) ) {
79
81
SetReturnValue ( value , false ) ;
80
82
return ;
81
83
}
84
+
82
85
// If return value is set from annotation, it should not be changing.
83
86
var currentType = StaticReturnValue . GetPythonType ( ) ;
84
87
var valueType = value . GetPythonType ( ) ;
@@ -98,6 +101,7 @@ internal void SetReturnValueProvider(ReturnValueProvider provider)
98
101
=> _returnValueProvider = provider ;
99
102
100
103
#region IPythonFunctionOverload
104
+
101
105
public FunctionDefinition FunctionDefinition { get ; }
102
106
public IPythonClassMember ClassMember { get ; }
103
107
public string Name { get ; }
@@ -113,38 +117,11 @@ public string Documentation {
113
117
}
114
118
115
119
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
+ }
148
125
}
149
126
return _returnDocumentation ;
150
127
}
@@ -161,59 +138,72 @@ public IMember Call(IArgumentSet args, IPythonType self, Node callLocation = nul
161
138
}
162
139
}
163
140
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
172
145
173
- var returnType = StaticReturnValue . GetPythonType ( ) ;
174
- switch ( returnType ) {
146
+ private IMember GetSpecificReturnType ( IPythonClassType selfClassType , IArgumentSet args ) {
147
+ var returnValueType = StaticReturnValue . GetPythonType ( ) ;
148
+ switch ( returnValueType ) {
175
149
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 ) ;
214
162
}
163
+
215
164
return StaticReturnValue ;
216
165
}
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
+ }
218
208
}
219
209
}
0 commit comments