f98a64d52d8696dc7d8f32967fd92bcddd90eff2
[mono.git] / mcs / gmcs / generic.cs
1 //
2 // generic.cs: Support classes for generics
3 //
4 // Author:
5 //   Miguel de Icaza (miguel@ximian.com)
6 //
7 // (C) 2003 Ximian, Inc.
8 //
9 using System;
10 using System.Reflection;
11 using System.Reflection.Emit;
12 using System.Globalization;
13 using System.Collections;
14 using System.Text;
15         
16 namespace Mono.CSharp {
17
18         //
19         // Tracks the constraints for a type parameter
20         //
21         public class Constraints {
22                 string type_parameter;
23                 ArrayList constraints;
24                 Location loc;
25                 
26                 //
27                 // type_parameter is the identifier, constraints is an arraylist of
28                 // Expressions (with types) or `true' for the constructor constraint.
29                 // 
30                 public Constraints (string type_parameter, ArrayList constraints,
31                                     Location loc)
32                 {
33                         this.type_parameter = type_parameter;
34                         this.constraints = constraints;
35                         this.loc = loc;
36                 }
37
38                 public string TypeParameter {
39                         get {
40                                 return type_parameter;
41                         }
42                 }
43
44                 protected void Error (string message)
45                 {
46                         Report.Error (-218, "Invalid constraints clause for type " +
47                                       "parameter `{0}': {1}", type_parameter, message);
48                 }
49
50                 bool has_ctor_constraint;
51                 Type class_constraint;
52                 ArrayList iface_constraints;
53                 Type[] constraint_types;
54                 int num_constraints;
55
56                 public bool HasConstructorConstraint {
57                         get { return has_ctor_constraint; }
58                 }
59
60                 public Type[] Types {
61                         get { return constraint_types; }
62                 }
63
64                 public bool Resolve (TypeContainer tc)
65                 {
66                         iface_constraints = new ArrayList ();
67
68                         if (constraints == null) {
69                                 constraint_types = new Type [0];
70                                 return true;
71                         }
72
73                         foreach (object obj in constraints) {
74                                 if (has_ctor_constraint) {
75                                         Error ("can only use one constructor constraint and " +
76                                                "it must be the last constraint in the list.");
77                                         return false;
78                                 }
79
80                                 if (obj is bool) {
81                                         has_ctor_constraint = true;
82                                         continue;
83                                 }
84
85                                 Expression expr = tc.ResolveTypeExpr ((Expression) obj, false, loc);
86                                 if (expr == null)
87                                         return false;
88
89                                 Type etype = expr.Type;
90                                 if (etype.IsInterface)
91                                         iface_constraints.Add (etype);
92                                 else if (class_constraint != null) {
93                                         Error ("can have at most one class constraint.");
94                                         return false;
95                                 } else
96                                         class_constraint = etype;
97
98                                 num_constraints++;
99                         }
100
101                         constraint_types = new Type [num_constraints];
102                         int pos = 0;
103                         if (class_constraint != null)
104                                 constraint_types [pos++] = class_constraint;
105                         iface_constraints.CopyTo (constraint_types, pos);
106
107                         return true;
108                 }
109         }
110
111         //
112         // This type represents a generic type parameter
113         //
114         public class TypeParameter {
115                 string name;
116                 Constraints constraints;
117                 Location loc;
118                 Type type;
119
120                 public TypeParameter (string name, Constraints constraints, Location loc)
121                 {
122                         this.name = name;
123                         this.constraints = constraints;
124                         this.loc = loc;
125                 }
126
127                 public string Name {
128                         get {
129                                 return name;
130                         }
131                 }
132
133                 public Location Location {
134                         get {
135                                 return loc;
136                         }
137                 }
138
139                 public Constraints Constraints {
140                         get {
141                                 return constraints;
142                         }
143                 }
144
145                 public Type Type {
146                         get {
147                                 return type;
148                         }
149                 }
150
151                 public bool Resolve (TypeContainer tc)
152                 {
153                         if (constraints != null)
154                                 return constraints.Resolve (tc);
155
156                         return true;
157                 }
158
159                 public Type Define (TypeBuilder tb)
160                 {
161                         if (constraints != null)
162                                 type = tb.DefineGenericParameter (name, constraints.Types);
163                         else
164                                 type = tb.DefineGenericParameter (name, new Type [0]);
165
166                         return type;
167                 }
168
169                 public Type DefineMethod (MethodBuilder mb)
170                 {
171                         if (constraints != null)
172                                 type = mb.DefineGenericParameter (name, constraints.Types);
173                         else
174                                 type = mb.DefineGenericParameter (name, new Type [0]);
175
176                         return type;
177                 }
178
179                 public override string ToString ()
180                 {
181                         return "TypeParameter[" + name + "]";
182                 }
183         }
184
185         //
186         // This type represents a generic type parameter reference.
187         //
188         // These expressions are born in a fully resolved state.
189         //
190         public class TypeParameterExpr : TypeExpr {
191                 TypeParameter type_parameter;
192
193                 public string Name {
194                         get {
195                                 return type_parameter.Name;
196                         }
197                 }
198
199                 public TypeParameter TypeParameter {
200                         get {
201                                 return type_parameter;
202                         }
203                 }
204                 
205                 public TypeParameterExpr (TypeParameter type_parameter, Location loc)
206                         : base (type_parameter.Type, loc)
207                 {
208                         this.type_parameter = type_parameter;
209                 }
210
211                 public override Expression ResolveAsTypeStep (EmitContext ec)
212                 {
213                         type = type_parameter.Type;
214
215                         return this;
216                 }
217
218                 public override string ToString ()
219                 {
220                         return "TypeParameterExpr[" + type_parameter.Name + "]";
221                 }
222
223                 public void Error_CannotUseAsUnmanagedType (Location loc)
224                 {
225                         Report.Error (-203, loc, "Can not use type parameter as unamanged type");
226                 }
227         }
228
229         public class TypeArguments {
230                 ArrayList args;
231                 Type[] atypes;
232                 bool has_type_args;
233                 
234                 public TypeArguments ()
235                 {
236                         args = new ArrayList ();
237                 }
238
239                 public void Add (Expression type)
240                 {
241                         args.Add (type);
242                 }
243
244                 public Type[] Arguments {
245                         get {
246                                 return atypes;
247                         }
248                 }
249
250                 public bool HasTypeArguments {
251                         get {
252                                 return has_type_args;
253                         }
254                 }
255
256                 public override string ToString ()
257                 {
258                         StringBuilder s = new StringBuilder ();
259
260                         int count = args.Count;
261                         for (int i = 0; i < count; i++){
262                                 //
263                                 // FIXME: Use TypeManager.CSharpname once we have the type
264                                 //
265                                 s.Append (args [i].ToString ());
266                                 if (i+1 < count)
267                                         s.Append (", ");
268                         }
269                         return s.ToString ();
270                 }
271
272                 public bool Resolve (EmitContext ec)
273                 {
274                         int count = args.Count;
275                         bool ok = true;
276
277                         atypes = new Type [count];
278                         
279                         for (int i = 0; i < count; i++){
280                                 Expression e = ((Expression)args [i]).ResolveAsTypeTerminal (ec);
281                                 if (e == null)
282                                         ok = false;
283                                 if (e is TypeParameterExpr)
284                                         has_type_args = true;
285                                 args [i] = e;
286                                 atypes [i] = e.Type;
287                         }
288                         return ok;
289                 }
290         }
291         
292         public class ConstructedType : Expression {
293                 Expression container_type;
294                 string name, full_name;
295                 TypeArguments args;
296                 Type[] gen_params, atypes;
297                 
298                 public ConstructedType (string name, TypeArguments args, Location l)
299                 {
300                         loc = l;
301                         this.container_type = container_type;
302                         this.name = name;
303                         this.args = args;
304                         eclass = ExprClass.Type;
305
306                         full_name = name + "<" + args.ToString () + ">";
307                 }
308
309                 public override Expression DoResolve (EmitContext ec)
310                 {
311                         if (args.Resolve (ec) == false)
312                                 return null;
313
314                         //
315                         // Pretend there are not type parameters, until we get GetType support
316                         //
317                         return new SimpleName (name, loc).DoResolve (ec);
318                 }
319
320                 protected bool CheckConstraints (int index)
321                 {
322                         Type atype = args.Arguments [index];
323                         Type ptype = gen_params [index];
324
325                         //// FIXME
326                         return true;
327
328                         //
329                         // First, check parent class.
330                         //
331                         if ((ptype.BaseType != atype.BaseType) &&
332                             !atype.BaseType.IsSubclassOf (ptype.BaseType)) {
333                                 Report.Error (-219, loc, "Cannot create constructed type `{0}': " +
334                                               "type argument `{1}' must derive from `{2}'.",
335                                               full_name, atype, ptype.BaseType);
336                                 return false;
337                         }
338
339                         //
340                         // Now, check the interfaces.
341                         //
342                         foreach (Type itype in ptype.GetInterfaces ()) {
343                                 if (TypeManager.ImplementsInterface (atype, itype))
344                                         continue;
345
346                                 Report.Error (-219, loc, "Cannot create constructed type `{0}: " +
347                                               "type argument `{1}' must implement interface `{2}'.",
348                                               full_name, atype, itype);
349                                 return false;
350                         }
351
352                         return true;
353                 }
354
355                 public override Expression ResolveAsTypeStep (EmitContext ec)
356                 {
357                         if (args.Resolve (ec) == false)
358                                 return null;
359
360                         //
361                         // First, resolve the generic type.
362                         //
363                         SimpleName sn = new SimpleName (name, loc);
364                         Expression resolved = sn.ResolveAsTypeStep (ec);
365                         if (resolved == null)
366                                 return null;
367
368                         Type gt = resolved.Type.GetGenericTypeDefinition ();
369                         gen_params = gt.GetGenericArguments ();
370                         atypes = args.Arguments;
371
372                         if (atypes.Length != gen_params.Length) {
373                                 Report.Error (-217, loc, "Generic type `{0}' takes {1} " +
374                                               "type parameters, but specified {2}.", gt.Name,
375                                               gen_params.Length, atypes.Length);
376                                 return null;
377                         }
378
379                         if (args.HasTypeArguments)
380                                 return new TypeExpr (gt, loc);
381
382                         for (int i = 0; i < gen_params.Length; i++) {
383                                 if (!CheckConstraints (i))
384                                         return null;
385                         }
386
387                         //
388                         // Now bind the parameters.
389                         //
390                         Type ntype = gt.BindGenericParameters (args.Arguments);
391                         return new TypeExpr (ntype, loc);
392                 }
393                 
394                 public override void Emit (EmitContext ec)
395                 {
396                         //
397                         // Never reached for now
398                         //
399                         throw new Exception ("IMPLEMENT ME");
400                 }
401
402                 public override string ToString ()
403                 {
404                         return full_name;
405                 }
406         }
407
408         public class GenericMethod : DeclSpace
409         {
410                 public GenericMethod (NamespaceEntry ns, TypeContainer parent, string name, Location l)
411                         : base (ns, parent, name, l)
412                 { }
413
414                 public override TypeBuilder DefineType ()
415                 {
416                         throw new Exception ();
417                 }
418
419                 public override bool Define (TypeContainer parent)
420                 {
421                         return true;
422                 }
423
424                 public bool Define (MethodBuilder mb)
425                 {
426                         Type[] gen_params = new Type [TypeParameters.Length];
427                         for (int i = 0; i < TypeParameters.Length; i++)
428                                 gen_params [i] = TypeParameters [i].DefineMethod (mb);
429
430                         return true;
431                 }
432
433                 public override bool DefineMembers (TypeContainer parent)
434                 {
435                         return true;
436                 }
437
438                 public override MemberList FindMembers (MemberTypes mt, BindingFlags bf,
439                                                         MemberFilter filter, object criteria)
440                 {
441                         throw new Exception ();
442                 }               
443
444                 public override MemberCache MemberCache {
445                         get {
446                                 throw new Exception ();
447                         }
448                 }
449         }
450
451         public class GenericMemberAccess : MemberAccess
452         {
453                 TypeArguments args;
454
455                 public GenericMemberAccess (Expression expr, string id, TypeArguments args, Location loc)
456                         : base (expr, id, loc)
457                 {
458                         this.args = args;
459                 }
460
461                 public override Expression DoResolve (EmitContext ec, Expression right_side,
462                                                       ResolveFlags flags)
463                 {
464                         Expression expr = base.DoResolve (ec, right_side, flags);
465                         if (expr == null)
466                                 return null;
467
468                         MethodGroupExpr mg = expr as MethodGroupExpr;
469                         if (mg == null) {
470                                 Report.Error (-220, loc, "Member `{0}' has type arguments, but did " +
471                                               "not resolve as a method group.", Identifier);
472                                 return null;
473                         }
474
475                         Report.Debug (64, "RESOLVE GENERIC MEMBER ACCESS", expr, expr.GetType ());
476
477                         return expr;
478                 }
479         }
480 }