2020using System . Text ;
2121using System . Threading . Tasks ;
2222using Microsoft . PythonTools . Analysis . Infrastructure ;
23+ using Microsoft . PythonTools . Analysis . Values ;
2324using Microsoft . PythonTools . Interpreter ;
2425
2526namespace Microsoft . PythonTools . Analysis {
2627 public class OverloadResult : IOverloadResult {
2728 private readonly ParameterResult [ ] _parameters ;
28- private readonly string [ ] _returnType ;
29+ private readonly IAnalysisSet _returnTypes ;
2930
30- public OverloadResult ( ParameterResult [ ] parameters , string name , string documentation , IEnumerable < string > returnType ) {
31+ public OverloadResult ( ParameterResult [ ] parameters , string name , string documentation , IAnalysisSet returnTypes ) {
3132 _parameters = parameters ;
3233 Name = name ;
3334 Documentation = documentation ;
34- _returnType = returnType . MaybeEnumerate ( ) . ToArray ( ) ;
35+ _returnTypes = returnTypes ;
3536 }
3637
3738 public string Name { get ; }
38- public virtual IReadOnlyList < string > ReturnType { get { return _returnType ; } }
39+ public virtual IReadOnlyList < string > ReturnType => _returnTypes . Select ( t => t . Name ) . ToArray ( ) ;
40+ public virtual IAnalysisSet ReturnTypes => _returnTypes ;
3941 public virtual string Documentation { get ; }
40- public virtual ParameterResult [ ] Parameters { get { return _parameters ; } }
42+ public virtual ParameterResult [ ] Parameters => _parameters ;
4143
42- internal virtual OverloadResult WithNewParameters ( ParameterResult [ ] newParameters ) {
43- return new OverloadResult ( newParameters , Name , Documentation , ReturnType ) ;
44- }
44+ internal virtual OverloadResult WithNewParameters ( ParameterResult [ ] newParameters )
45+ => new OverloadResult ( newParameters , Name , Documentation , ReturnTypes ) ;
4546
46- internal virtual OverloadResult WithoutLeadingParameters ( int skipCount = 1 ) {
47- return new OverloadResult ( _parameters . Skip ( skipCount ) . ToArray ( ) , Name , Documentation , _returnType ) ;
48- }
47+ internal virtual OverloadResult WithoutLeadingParameters ( int skipCount = 1 )
48+ => new OverloadResult ( _parameters . Skip ( skipCount ) . ToArray ( ) , Name , Documentation , _returnTypes ) ;
4949
5050 private static string Longest ( string x , string y ) {
5151 if ( x == null ) {
@@ -84,11 +84,8 @@ private static IEnumerable<string> CommaSplit(string x) {
8484 }
8585 }
8686
87- private static string Merge ( string x , string y ) {
88- return string . Join ( ", " ,
89- CommaSplit ( x ) . Concat ( CommaSplit ( y ) ) . OrderBy ( n => n ) . Distinct ( )
90- ) ;
91- }
87+ private static string Merge ( string x , string y )
88+ => string . Join ( ", " , CommaSplit ( x ) . Concat ( CommaSplit ( y ) ) . OrderBy ( n => n ) . Distinct ( ) ) ;
9289
9390 public static OverloadResult Merge ( IEnumerable < OverloadResult > overloads ) {
9491 overloads = overloads . ToArray ( ) ;
@@ -117,18 +114,29 @@ public static OverloadResult Merge(IEnumerable<OverloadResult> overloads) {
117114
118115 return res ;
119116 } ) ;
120- var returnType = overloads . SelectMany ( o => o . ReturnType ) . Distinct ( ) ;
121117
122- return new OverloadResult ( parameters , name , doc , returnType ) ;
118+ var returnTypes = overloads . SelectMany ( o => o . ReturnTypes ) . Distinct ( ) ;
119+ return new OverloadResult ( parameters , name , doc , AnalysisSet . Create ( returnTypes ) ) ;
123120 }
124121
125122 public override string ToString ( ) {
126- return "{0}({1})->[{2}]{3}" . FormatInvariant (
127- Name ,
128- string . Join ( "," , Parameters . Select ( p => "{0}{1}:{2}={3}" . FormatInvariant ( p . Name , p . IsOptional ? "?" : "" , p . Type ?? "" , p . DefaultValue ?? "" ) ) ) ,
129- string . Join ( "," , ReturnType . OrderBy ( k => k ) ) ,
130- string . IsNullOrEmpty ( Documentation ) ? "" : ( "'''{0}'''" . FormatInvariant ( Documentation ) )
123+ var parameters = string . Join ( ", " ,
124+ Parameters . Select ( p => "{0}{1}:{2}{3}{4}"
125+ . FormatInvariant ( p . Name ,
126+ p . IsOptional ? "?" : string . Empty ,
127+ p . Type ?? string . Empty ,
128+ p . DefaultValue != null ? "=" : string . Empty ,
129+ p . DefaultValue ?? string . Empty ) )
130+ ) . TrimEnd ( ) ;
131+
132+ var returnType = "{0}{1}{2}" . FormatInvariant (
133+ ReturnType . Count > 1 ? "[" : string . Empty ,
134+ ReturnType . Count > 0 ? string . Join ( "," , ReturnType . OrderBy ( k => k ) ) : "None" ,
135+ ReturnType . Count > 1 ? "]" : string . Empty
131136 ) ;
137+
138+ var doc = string . IsNullOrEmpty ( Documentation ) ? "" : "'''{0}'''" . FormatInvariant ( Documentation ) ;
139+ return "{0}({1}) -> {2}{3}" . FormatInvariant ( Name , parameters , returnType , doc ) ;
132140 }
133141 }
134142
@@ -138,7 +146,7 @@ class AccumulatedOverloadResult {
138146 private string [ ] _pnames ;
139147 private IAnalysisSet [ ] _ptypes ;
140148 private string [ ] _pdefaults ;
141- private readonly HashSet < string > _rtypes ;
149+ private IAnalysisSet _rtypes ;
142150
143151 public AccumulatedOverloadResult ( string name , string documentation , int parameters ) {
144152 _name = name ;
@@ -147,14 +155,13 @@ public AccumulatedOverloadResult(string name, string documentation, int paramete
147155 _ptypes = new IAnalysisSet [ parameters ] ;
148156 _pdefaults = new string [ parameters ] ;
149157 ParameterCount = parameters ;
150- _rtypes = new HashSet < string > ( ) ;
158+ _rtypes = AnalysisSet . Empty ;
151159 }
152160
153161 public int ParameterCount { get ; }
154162
155- private bool AreNullOrEqual ( string x , string y ) {
156- return string . IsNullOrEmpty ( x ) || string . IsNullOrEmpty ( y ) || string . Equals ( x , y , StringComparison . Ordinal ) ;
157- }
163+ private bool AreNullOrEqual ( string x , string y ) =>
164+ string . IsNullOrEmpty ( x ) || string . IsNullOrEmpty ( y ) || string . Equals ( x , y , StringComparison . Ordinal ) ;
158165
159166 private bool AreNullOrEqual ( IAnalysisSet x , IAnalysisSet y ) {
160167 return x == null || x . IsObjectOrUnknown ( ) ||
@@ -174,15 +181,15 @@ private string ChooseBest(string x, string y) {
174181
175182 private IAnalysisSet ChooseBest ( IAnalysisSet x , IAnalysisSet y ) {
176183 if ( x == null || x . IsObjectOrUnknown ( ) ) {
177- return ( y == null || y . IsObjectOrUnknown ( ) ) ? AnalysisSet . Empty : y ;
184+ return ( y == null ) ? AnalysisSet . Empty : y ;
178185 }
179186 if ( y == null || y . IsObjectOrUnknown ( ) ) {
180- return AnalysisSet . Empty ;
187+ return null ;
181188 }
182- return x . Union ( y ) ;
189+ return MergeTypes ( x , y ) ;
183190 }
184191
185- public bool TryAddOverload ( string name , string documentation , string [ ] names , IAnalysisSet [ ] types , string [ ] defaults , IEnumerable < string > returnTypes ) {
192+ public bool TryAddOverload ( string name , string documentation , string [ ] names , IAnalysisSet [ ] types , string [ ] defaults , IAnalysisSet returnTypes ) {
186193 if ( names . Length != _pnames . Length || types . Length != _ptypes . Length ) {
187194 return false ;
188195 }
@@ -210,7 +217,7 @@ public bool TryAddOverload(string name, string documentation, string[] names, IA
210217 }
211218
212219 if ( returnTypes != null ) {
213- _rtypes . UnionWith ( returnTypes ) ;
220+ _rtypes = ChooseBest ( _rtypes , returnTypes ) ;
214221 }
215222
216223 return true ;
@@ -234,6 +241,27 @@ public OverloadResult ToOverloadResult() {
234241 }
235242 return new OverloadResult ( parameters , _name , _doc , _rtypes ) ;
236243 }
244+
245+ private IAnalysisSet MergeTypes ( IAnalysisSet x , IAnalysisSet y ) {
246+ // Merge types so we get simple parameter description such as
247+ // list[int] rather than duplicates such as list[int],list[int, int, int].
248+ var cmp = UnionComparer . Instances [ 1 ] ;
249+ var xA = x . ToArray ( ) ;
250+ var yA = y . ToArray ( ) ;
251+ var mergedValues = new List < AnalysisValue > ( ) ;
252+ for ( var i = 0 ; i < xA . Length ; i ++ ) {
253+ // Order types for merging in the order of description length
254+ // so more complex type would possibly fold into the simpler type
255+ // such as list[int, int, int] will fold into the list[int].
256+
257+ // TODO: this is not bulletproof.
258+ // For example, it will merge user type derived from int into the int.
259+ var xd = string . Join ( "," , xA [ i ] . GetShortDescriptions ( ) ) ;
260+ var yd = string . Join ( "," , yA [ i ] . GetShortDescriptions ( ) ) ;
261+ mergedValues . Add ( xd . Length < yd . Length ? cmp . MergeTypes ( xA [ i ] , yA [ i ] , out _ ) : cmp . MergeTypes ( yA [ i ] , xA [ i ] , out _ ) ) ;
262+ }
263+ return AnalysisSet . CreateUnion ( mergedValues , cmp ) ;
264+ }
237265 }
238266
239267 class BuiltinFunctionOverloadResult : OverloadResult {
@@ -245,7 +273,6 @@ class BuiltinFunctionOverloadResult : OverloadResult {
245273 private readonly Func < string > _fallbackDoc ;
246274 private string _doc ;
247275 private IReadOnlyList < string > _returnTypes ;
248- private static readonly string _calculating = "Documentation is still being calculated, please try again soon." ;
249276
250277 // Used by ToString to ensure docs have completed
251278 private Task _docTask ;
@@ -306,7 +333,7 @@ public override string Documentation {
306333
307334 private void Calculate ( ) {
308335 // initially fill in w/ a string saying we don't yet have the documentation
309- _doc = _calculating ;
336+ _doc = Resources . CalculatingDocumentation ;
310337 _docTask = Task . Factory . StartNew ( DocCalculator ) ;
311338 }
312339
0 commit comments