|
16 | 16 | using System; |
17 | 17 | using System.Collections.Generic; |
18 | 18 | using System.Linq; |
| 19 | +using Microsoft.Python.Analysis.Diagnostics; |
19 | 20 | using Microsoft.Python.Analysis.Specializations.Typing; |
20 | 21 | using Microsoft.Python.Analysis.Specializations.Typing.Types; |
21 | 22 | using Microsoft.Python.Analysis.Types; |
22 | 23 | using Microsoft.Python.Analysis.Values; |
23 | 24 | using Microsoft.Python.Core; |
| 25 | +using Microsoft.Python.Parsing; |
24 | 26 | using Microsoft.Python.Parsing.Ast; |
| 27 | +using ErrorCodes = Microsoft.Python.Analysis.Diagnostics.ErrorCodes; |
25 | 28 |
|
26 | 29 | namespace Microsoft.Python.Analysis.Analyzer.Evaluation { |
27 | 30 | internal sealed partial class ExpressionEval { |
@@ -59,40 +62,58 @@ private IMember GetValueFromGeneric(IMember target, Expression expr) { |
59 | 62 | } |
60 | 63 |
|
61 | 64 | /// <summary> |
62 | | - /// Given generic type and list of indices in the expression like |
63 | | - /// Generic[T1, T2, ...] or List[str] creates generic class base |
64 | | - /// (if the former) on specific type (if the latter). |
| 65 | + /// Returns whether the arguments to Generic are valid |
65 | 66 | /// </summary> |
66 | | - private IMember CreateSpecificTypeFromIndex(IGenericType gt, IReadOnlyList<IMember> indices, Expression expr) { |
67 | | - // See which ones are generic parameters as defined by TypeVar() |
68 | | - // and which are specific types. Normally there should not be a mix. |
69 | | - var genericTypeArgs = indices.OfType<IGenericTypeDefinition>().ToArray(); |
70 | | - var specificTypes = indices.Where(i => !(i is IGenericTypeDefinition)).OfType<IPythonType>().ToArray(); |
71 | | - |
72 | | - if (genericTypeArgs.Length > 0 && genericTypeArgs.Length != indices.Count) { |
73 | | - // TODO: report that some type arguments are not declared with TypeVar. |
| 67 | + private bool GenericClassParameterValid(IReadOnlyList<IGenericTypeDefinition> genericTypeArgs, IReadOnlyList<IMember> args, Expression expr) { |
| 68 | + // All arguments to Generic must be type parameters |
| 69 | + // e.g. Generic[T, str] throws a runtime error |
| 70 | + if (genericTypeArgs.Count != args.Count) { |
| 71 | + ReportDiagnostics(Module.Uri, new DiagnosticsEntry( |
| 72 | + Resources.GenericNotAllTypeParameters, |
| 73 | + GetLocation(expr).Span, |
| 74 | + ErrorCodes.TypingGenericArguments, |
| 75 | + Severity.Error, |
| 76 | + DiagnosticSource.Analysis)); |
| 77 | + return false; |
74 | 78 | } |
75 | | - if (specificTypes.Length > 0 && specificTypes.Length != indices.Count) { |
76 | | - // TODO: report that arguments are not specific types or are not declared. |
| 79 | + |
| 80 | + // All arguments to Generic must be distinct |
| 81 | + if (genericTypeArgs.Distinct().Count() != genericTypeArgs.Count) { |
| 82 | + ReportDiagnostics(Module.Uri, new DiagnosticsEntry( |
| 83 | + Resources.GenericNotAllUnique, |
| 84 | + GetLocation(expr).Span, |
| 85 | + ErrorCodes.TypingGenericArguments, |
| 86 | + Severity.Error, |
| 87 | + DiagnosticSource.Analysis)); |
| 88 | + return false; |
77 | 89 | } |
78 | 90 |
|
| 91 | + return true; |
| 92 | + } |
| 93 | + |
| 94 | + /// <summary> |
| 95 | + /// Given generic type and list of arguments in the expression like |
| 96 | + /// Generic[T1, T2, ...] or List[str] creates generic class base |
| 97 | + /// (if the former) on specific type (if the latter). |
| 98 | + /// </summary> |
| 99 | + private IMember CreateSpecificTypeFromIndex(IGenericType gt, IReadOnlyList<IMember> args, Expression expr) { |
| 100 | + var genericTypeArgs = args.OfType<IGenericTypeDefinition>().ToArray(); |
| 101 | + |
79 | 102 | if (gt.Name.EqualsOrdinal("Generic")) { |
80 | | - // Generic[T1, T2, ...] expression. Create generic base for the class. |
81 | | - if (genericTypeArgs.Length > 0) { |
82 | | - return new GenericClassParameter(genericTypeArgs, Module); |
83 | | - } else { |
84 | | - // TODO: report too few type arguments for Generic[]. |
| 103 | + if (!GenericClassParameterValid(genericTypeArgs, args, expr)) { |
85 | 104 | return UnknownType; |
86 | 105 | } |
| 106 | + |
| 107 | + // Generic[T1, T2, ...] expression. Create generic base for the class. |
| 108 | + return new GenericClassParameter(genericTypeArgs, Module); |
87 | 109 | } |
88 | 110 |
|
89 | 111 | // For other types just use supplied arguments |
90 | | - if (indices.Count > 0) { |
91 | | - return gt.CreateSpecificType(new ArgumentSet(indices, expr, this)); |
| 112 | + if (args.Count > 0) { |
| 113 | + return gt.CreateSpecificType(new ArgumentSet(args, expr, this)); |
92 | 114 | } |
93 | | - // TODO: report too few type arguments for the generic expression. |
94 | | - return UnknownType; |
95 | 115 |
|
| 116 | + return UnknownType; |
96 | 117 | } |
97 | 118 |
|
98 | 119 | private IReadOnlyList<IMember> EvaluateIndex(IndexExpression expr) { |
@@ -194,7 +215,7 @@ private static IReadOnlyList<IPythonType> GetSpecificTypeFromArgumentValue(objec |
194 | 215 | var itemType = iter.GetIterator().Next.GetPythonType(); |
195 | 216 | if (!itemType.IsUnknown()) { |
196 | 217 | specificTypes.Add(itemType); |
197 | | - } else if(argumentValue is IPythonInstance inst) { |
| 218 | + } else if (argumentValue is IPythonInstance inst) { |
198 | 219 | specificTypes.Add(inst.GetPythonType()); |
199 | 220 | } |
200 | 221 | break; |
|
0 commit comments