1 | // |
---|
2 | // generic.cs: Generics support |
---|
3 | // |
---|
4 | // Authors: Martin Baulig (martin@ximian.com) |
---|
5 | // Miguel de Icaza (miguel@ximian.com) |
---|
6 | // Marek Safar (marek.safar@gmail.com) |
---|
7 | // |
---|
8 | // Dual licensed under the terms of the MIT X11 or GNU GPL |
---|
9 | // |
---|
10 | // Copyright 2001, 2002, 2003 Ximian, Inc (http://www.ximian.com) |
---|
11 | // Copyright 2004-2008 Novell, Inc |
---|
12 | // Copyright 2011 Xamarin, Inc (http://www.xamarin.com) |
---|
13 | // |
---|
14 | |
---|
15 | using System; |
---|
16 | using System.Collections.Generic; |
---|
17 | using System.Text; |
---|
18 | using System.Linq; |
---|
19 | |
---|
20 | #if STATIC |
---|
21 | using MetaType = IKVM.Reflection.Type; |
---|
22 | using IKVM.Reflection; |
---|
23 | using IKVM.Reflection.Emit; |
---|
24 | #else |
---|
25 | using MetaType = System.Type; |
---|
26 | using System.Reflection; |
---|
27 | using System.Reflection.Emit; |
---|
28 | #endif |
---|
29 | |
---|
30 | namespace Mono.CSharp { |
---|
31 | public class VarianceDecl |
---|
32 | { |
---|
33 | public VarianceDecl (Variance variance, Location loc) |
---|
34 | { |
---|
35 | this.Variance = variance; |
---|
36 | this.Location = loc; |
---|
37 | } |
---|
38 | |
---|
39 | public Variance Variance { get; private set; } |
---|
40 | public Location Location { get; private set; } |
---|
41 | |
---|
42 | public static Variance CheckTypeVariance (TypeSpec t, Variance expected, IMemberContext member) |
---|
43 | { |
---|
44 | var tp = t as TypeParameterSpec; |
---|
45 | if (tp != null) { |
---|
46 | var v = tp.Variance; |
---|
47 | if (expected == Variance.None && v != expected || |
---|
48 | expected == Variance.Covariant && v == Variance.Contravariant || |
---|
49 | expected == Variance.Contravariant && v == Variance.Covariant) { |
---|
50 | ((TypeParameter) tp.MemberDefinition).ErrorInvalidVariance (member, expected); |
---|
51 | } |
---|
52 | |
---|
53 | return expected; |
---|
54 | } |
---|
55 | |
---|
56 | if (t.TypeArguments.Length > 0) { |
---|
57 | var targs_definition = t.MemberDefinition.TypeParameters; |
---|
58 | TypeSpec[] targs = TypeManager.GetTypeArguments (t); |
---|
59 | for (int i = 0; i < targs.Length; ++i) { |
---|
60 | var v = targs_definition[i].Variance; |
---|
61 | CheckTypeVariance (targs[i], (Variance) ((int) v * (int) expected), member); |
---|
62 | } |
---|
63 | |
---|
64 | return expected; |
---|
65 | } |
---|
66 | |
---|
67 | var ac = t as ArrayContainer; |
---|
68 | if (ac != null) |
---|
69 | return CheckTypeVariance (ac.Element, expected, member); |
---|
70 | |
---|
71 | return Variance.None; |
---|
72 | } |
---|
73 | } |
---|
74 | |
---|
75 | public enum Variance |
---|
76 | { |
---|
77 | // |
---|
78 | // Don't add or modify internal values, they are used as -/+ calculation signs |
---|
79 | // |
---|
80 | None = 0, |
---|
81 | Covariant = 1, |
---|
82 | Contravariant = -1 |
---|
83 | } |
---|
84 | |
---|
85 | [Flags] |
---|
86 | public enum SpecialConstraint |
---|
87 | { |
---|
88 | None = 0, |
---|
89 | Constructor = 1 << 2, |
---|
90 | Class = 1 << 3, |
---|
91 | Struct = 1 << 4 |
---|
92 | } |
---|
93 | |
---|
94 | public class SpecialContraintExpr : FullNamedExpression |
---|
95 | { |
---|
96 | public SpecialContraintExpr (SpecialConstraint constraint, Location loc) |
---|
97 | { |
---|
98 | this.loc = loc; |
---|
99 | this.Constraint = constraint; |
---|
100 | } |
---|
101 | |
---|
102 | public SpecialConstraint Constraint { get; private set; } |
---|
103 | |
---|
104 | protected override Expression DoResolve (ResolveContext rc) |
---|
105 | { |
---|
106 | throw new NotImplementedException (); |
---|
107 | } |
---|
108 | |
---|
109 | public override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc, bool allowUnboundTypeArguments) |
---|
110 | { |
---|
111 | throw new NotImplementedException (); |
---|
112 | } |
---|
113 | } |
---|
114 | |
---|
115 | // |
---|
116 | // A set of parsed constraints for a type parameter |
---|
117 | // |
---|
118 | public class Constraints |
---|
119 | { |
---|
120 | readonly SimpleMemberName tparam; |
---|
121 | readonly List<FullNamedExpression> constraints; |
---|
122 | readonly Location loc; |
---|
123 | bool resolved; |
---|
124 | bool resolving; |
---|
125 | |
---|
126 | public IEnumerable<FullNamedExpression> ConstraintExpressions { |
---|
127 | get { |
---|
128 | return constraints; |
---|
129 | } |
---|
130 | } |
---|
131 | |
---|
132 | public Constraints (SimpleMemberName tparam, List<FullNamedExpression> constraints, Location loc) |
---|
133 | { |
---|
134 | this.tparam = tparam; |
---|
135 | this.constraints = constraints; |
---|
136 | this.loc = loc; |
---|
137 | } |
---|
138 | |
---|
139 | #region Properties |
---|
140 | |
---|
141 | public List<FullNamedExpression> TypeExpressions { |
---|
142 | get { |
---|
143 | return constraints; |
---|
144 | } |
---|
145 | } |
---|
146 | |
---|
147 | public Location Location { |
---|
148 | get { |
---|
149 | return loc; |
---|
150 | } |
---|
151 | } |
---|
152 | |
---|
153 | public SimpleMemberName TypeParameter { |
---|
154 | get { |
---|
155 | return tparam; |
---|
156 | } |
---|
157 | } |
---|
158 | |
---|
159 | #endregion |
---|
160 | |
---|
161 | public static bool CheckConflictingInheritedConstraint (TypeParameterSpec spec, TypeSpec bb, IMemberContext context, Location loc) |
---|
162 | { |
---|
163 | if (spec.HasSpecialClass && bb.IsStruct) { |
---|
164 | context.Module.Compiler.Report.Error (455, loc, |
---|
165 | "Type parameter `{0}' inherits conflicting constraints `{1}' and `{2}'", |
---|
166 | spec.Name, "class", bb.GetSignatureForError ()); |
---|
167 | |
---|
168 | return false; |
---|
169 | } |
---|
170 | |
---|
171 | return CheckConflictingInheritedConstraint (spec, spec.BaseType, bb, context, loc); |
---|
172 | } |
---|
173 | |
---|
174 | static bool CheckConflictingInheritedConstraint (TypeParameterSpec spec, TypeSpec ba, TypeSpec bb, IMemberContext context, Location loc) |
---|
175 | { |
---|
176 | if (ba == bb) |
---|
177 | return true; |
---|
178 | |
---|
179 | if (TypeSpec.IsBaseClass (ba, bb, false) || TypeSpec.IsBaseClass (bb, ba, false)) |
---|
180 | return true; |
---|
181 | |
---|
182 | Error_ConflictingConstraints (context, spec, ba, bb, loc); |
---|
183 | return false; |
---|
184 | } |
---|
185 | |
---|
186 | public static void Error_ConflictingConstraints (IMemberContext context, TypeParameterSpec tp, TypeSpec ba, TypeSpec bb, Location loc) |
---|
187 | { |
---|
188 | context.Module.Compiler.Report.Error (455, loc, |
---|
189 | "Type parameter `{0}' inherits conflicting constraints `{1}' and `{2}'", |
---|
190 | tp.Name, ba.GetSignatureForError (), bb.GetSignatureForError ()); |
---|
191 | } |
---|
192 | |
---|
193 | public void CheckGenericConstraints (IMemberContext context, bool obsoleteCheck) |
---|
194 | { |
---|
195 | foreach (var c in constraints) { |
---|
196 | if (c == null) |
---|
197 | continue; |
---|
198 | |
---|
199 | var t = c.Type; |
---|
200 | if (t == null) |
---|
201 | continue; |
---|
202 | |
---|
203 | if (obsoleteCheck) { |
---|
204 | ObsoleteAttribute obsolete_attr = t.GetAttributeObsolete (); |
---|
205 | if (obsolete_attr != null) |
---|
206 | AttributeTester.Report_ObsoleteMessage (obsolete_attr, t.GetSignatureForError (), c.Location, context.Module.Compiler.Report); |
---|
207 | } |
---|
208 | |
---|
209 | ConstraintChecker.Check (context, t, c.Location); |
---|
210 | } |
---|
211 | } |
---|
212 | |
---|
213 | // |
---|
214 | // Resolve the constraints types with only possible early checks, return |
---|
215 | // value `false' is reserved for recursive failure |
---|
216 | // |
---|
217 | public bool Resolve (IMemberContext context, TypeParameter tp) |
---|
218 | { |
---|
219 | if (resolved) |
---|
220 | return true; |
---|
221 | |
---|
222 | if (resolving) |
---|
223 | return false; |
---|
224 | |
---|
225 | resolving = true; |
---|
226 | var spec = tp.Type; |
---|
227 | List<TypeParameterSpec> tparam_types = null; |
---|
228 | bool iface_found = false; |
---|
229 | |
---|
230 | spec.BaseType = context.Module.Compiler.BuiltinTypes.Object; |
---|
231 | |
---|
232 | for (int i = 0; i < constraints.Count; ++i) { |
---|
233 | var constraint = constraints[i]; |
---|
234 | |
---|
235 | if (constraint is SpecialContraintExpr) { |
---|
236 | spec.SpecialConstraint |= ((SpecialContraintExpr) constraint).Constraint; |
---|
237 | if (spec.HasSpecialStruct) |
---|
238 | spec.BaseType = context.Module.Compiler.BuiltinTypes.ValueType; |
---|
239 | |
---|
240 | // Set to null as it does not have a type |
---|
241 | constraints[i] = null; |
---|
242 | continue; |
---|
243 | } |
---|
244 | |
---|
245 | var type = constraint.ResolveAsType (context); |
---|
246 | if (type == null) |
---|
247 | continue; |
---|
248 | |
---|
249 | if (type.Arity > 0 && ((InflatedTypeSpec) type).HasDynamicArgument ()) { |
---|
250 | context.Module.Compiler.Report.Error (1968, constraint.Location, |
---|
251 | "A constraint cannot be the dynamic type `{0}'", type.GetSignatureForError ()); |
---|
252 | continue; |
---|
253 | } |
---|
254 | |
---|
255 | if (!context.CurrentMemberDefinition.IsAccessibleAs (type)) { |
---|
256 | context.Module.Compiler.Report.SymbolRelatedToPreviousError (type); |
---|
257 | context.Module.Compiler.Report.Error (703, loc, |
---|
258 | "Inconsistent accessibility: constraint type `{0}' is less accessible than `{1}'", |
---|
259 | type.GetSignatureForError (), context.GetSignatureForError ()); |
---|
260 | } |
---|
261 | |
---|
262 | if (type.IsInterface) { |
---|
263 | if (!spec.AddInterface (type)) { |
---|
264 | context.Module.Compiler.Report.Error (405, constraint.Location, |
---|
265 | "Duplicate constraint `{0}' for type parameter `{1}'", type.GetSignatureForError (), tparam.Value); |
---|
266 | } |
---|
267 | |
---|
268 | iface_found = true; |
---|
269 | continue; |
---|
270 | } |
---|
271 | |
---|
272 | var constraint_tp = type as TypeParameterSpec; |
---|
273 | if (constraint_tp != null) { |
---|
274 | if (tparam_types == null) { |
---|
275 | tparam_types = new List<TypeParameterSpec> (2); |
---|
276 | } else if (tparam_types.Contains (constraint_tp)) { |
---|
277 | context.Module.Compiler.Report.Error (405, constraint.Location, |
---|
278 | "Duplicate constraint `{0}' for type parameter `{1}'", type.GetSignatureForError (), tparam.Value); |
---|
279 | continue; |
---|
280 | } |
---|
281 | |
---|
282 | // |
---|
283 | // Checks whether each generic method parameter constraint type |
---|
284 | // is valid with respect to T |
---|
285 | // |
---|
286 | if (tp.IsMethodTypeParameter) { |
---|
287 | VarianceDecl.CheckTypeVariance (type, Variance.Contravariant, context); |
---|
288 | } |
---|
289 | |
---|
290 | var tp_def = constraint_tp.MemberDefinition as TypeParameter; |
---|
291 | if (tp_def != null && !tp_def.ResolveConstraints (context)) { |
---|
292 | context.Module.Compiler.Report.Error (454, constraint.Location, |
---|
293 | "Circular constraint dependency involving `{0}' and `{1}'", |
---|
294 | constraint_tp.GetSignatureForError (), tp.GetSignatureForError ()); |
---|
295 | continue; |
---|
296 | } |
---|
297 | |
---|
298 | // |
---|
299 | // Checks whether there are no conflicts between type parameter constraints |
---|
300 | // |
---|
301 | // class Foo<T, U> |
---|
302 | // where T : A |
---|
303 | // where U : B, T |
---|
304 | // |
---|
305 | // A and B are not convertible and only 1 class constraint is allowed |
---|
306 | // |
---|
307 | if (constraint_tp.HasTypeConstraint) { |
---|
308 | if (spec.HasTypeConstraint || spec.HasSpecialStruct) { |
---|
309 | if (!CheckConflictingInheritedConstraint (spec, constraint_tp.BaseType, context, constraint.Location)) |
---|
310 | continue; |
---|
311 | } else { |
---|
312 | for (int ii = 0; ii < tparam_types.Count; ++ii) { |
---|
313 | if (!tparam_types[ii].HasTypeConstraint) |
---|
314 | continue; |
---|
315 | |
---|
316 | if (!CheckConflictingInheritedConstraint (spec, tparam_types[ii].BaseType, constraint_tp.BaseType, context, constraint.Location)) |
---|
317 | break; |
---|
318 | } |
---|
319 | } |
---|
320 | } |
---|
321 | |
---|
322 | if (constraint_tp.TypeArguments != null) { |
---|
323 | var eb = constraint_tp.GetEffectiveBase (); |
---|
324 | if (eb != null && !CheckConflictingInheritedConstraint (spec, eb, spec.BaseType, context, constraint.Location)) |
---|
325 | break; |
---|
326 | } |
---|
327 | |
---|
328 | if (constraint_tp.HasSpecialStruct) { |
---|
329 | context.Module.Compiler.Report.Error (456, constraint.Location, |
---|
330 | "Type parameter `{0}' has the `struct' constraint, so it cannot be used as a constraint for `{1}'", |
---|
331 | constraint_tp.GetSignatureForError (), tp.GetSignatureForError ()); |
---|
332 | continue; |
---|
333 | } |
---|
334 | |
---|
335 | tparam_types.Add (constraint_tp); |
---|
336 | continue; |
---|
337 | } |
---|
338 | |
---|
339 | if (iface_found || spec.HasTypeConstraint) { |
---|
340 | context.Module.Compiler.Report.Error (406, constraint.Location, |
---|
341 | "The class type constraint `{0}' must be listed before any other constraints. Consider moving type constraint to the beginning of the constraint list", |
---|
342 | type.GetSignatureForError ()); |
---|
343 | } |
---|
344 | |
---|
345 | if (spec.HasSpecialStruct || spec.HasSpecialClass) { |
---|
346 | context.Module.Compiler.Report.Error (450, constraint.Location, |
---|
347 | "`{0}': cannot specify both a constraint class and the `class' or `struct' constraint", |
---|
348 | type.GetSignatureForError ()); |
---|
349 | } |
---|
350 | |
---|
351 | switch (type.BuiltinType) { |
---|
352 | case BuiltinTypeSpec.Type.Array: |
---|
353 | case BuiltinTypeSpec.Type.Delegate: |
---|
354 | case BuiltinTypeSpec.Type.MulticastDelegate: |
---|
355 | case BuiltinTypeSpec.Type.Enum: |
---|
356 | case BuiltinTypeSpec.Type.ValueType: |
---|
357 | case BuiltinTypeSpec.Type.Object: |
---|
358 | context.Module.Compiler.Report.Error (702, constraint.Location, |
---|
359 | "A constraint cannot be special class `{0}'", type.GetSignatureForError ()); |
---|
360 | continue; |
---|
361 | case BuiltinTypeSpec.Type.Dynamic: |
---|
362 | context.Module.Compiler.Report.Error (1967, constraint.Location, |
---|
363 | "A constraint cannot be the dynamic type"); |
---|
364 | continue; |
---|
365 | } |
---|
366 | |
---|
367 | if (type.IsSealed || !type.IsClass) { |
---|
368 | context.Module.Compiler.Report.Error (701, loc, |
---|
369 | "`{0}' is not a valid constraint. A constraint must be an interface, a non-sealed class or a type parameter", |
---|
370 | type.GetSignatureForError ()); |
---|
371 | continue; |
---|
372 | } |
---|
373 | |
---|
374 | if (type.IsStatic) { |
---|
375 | context.Module.Compiler.Report.Error (717, constraint.Location, |
---|
376 | "`{0}' is not a valid constraint. Static classes cannot be used as constraints", |
---|
377 | type.GetSignatureForError ()); |
---|
378 | } |
---|
379 | |
---|
380 | spec.BaseType = type; |
---|
381 | } |
---|
382 | |
---|
383 | if (tparam_types != null) |
---|
384 | spec.TypeArguments = tparam_types.ToArray (); |
---|
385 | |
---|
386 | resolving = false; |
---|
387 | resolved = true; |
---|
388 | return true; |
---|
389 | } |
---|
390 | |
---|
391 | public void VerifyClsCompliance (Report report) |
---|
392 | { |
---|
393 | foreach (var c in constraints) |
---|
394 | { |
---|
395 | if (c == null) |
---|
396 | continue; |
---|
397 | |
---|
398 | if (!c.Type.IsCLSCompliant ()) { |
---|
399 | report.SymbolRelatedToPreviousError (c.Type); |
---|
400 | report.Warning (3024, 1, loc, "Constraint type `{0}' is not CLS-compliant", |
---|
401 | c.Type.GetSignatureForError ()); |
---|
402 | } |
---|
403 | } |
---|
404 | } |
---|
405 | } |
---|
406 | |
---|
407 | // |
---|
408 | // A type parameter for a generic type or generic method definition |
---|
409 | // |
---|
410 | public class TypeParameter : MemberCore, ITypeDefinition |
---|
411 | { |
---|
412 | static readonly string[] attribute_target = { "type parameter" }; |
---|
413 | |
---|
414 | Constraints constraints; |
---|
415 | GenericTypeParameterBuilder builder; |
---|
416 | readonly TypeParameterSpec spec; |
---|
417 | |
---|
418 | public TypeParameter (int index, MemberName name, Constraints constraints, Attributes attrs, Variance Variance) |
---|
419 | : base (null, name, attrs) |
---|
420 | { |
---|
421 | this.constraints = constraints; |
---|
422 | this.spec = new TypeParameterSpec (null, index, this, SpecialConstraint.None, Variance, null); |
---|
423 | } |
---|
424 | |
---|
425 | // |
---|
426 | // Used by parser |
---|
427 | // |
---|
428 | public TypeParameter (MemberName name, Attributes attrs, VarianceDecl variance) |
---|
429 | : base (null, name, attrs) |
---|
430 | { |
---|
431 | var var = variance == null ? Variance.None : variance.Variance; |
---|
432 | this.spec = new TypeParameterSpec (null, -1, this, SpecialConstraint.None, var, null); |
---|
433 | this.VarianceDecl = variance; |
---|
434 | } |
---|
435 | |
---|
436 | public TypeParameter (TypeParameterSpec spec, TypeSpec parentSpec, MemberName name, Attributes attrs) |
---|
437 | : base (null, name, attrs) |
---|
438 | { |
---|
439 | this.spec = new TypeParameterSpec (parentSpec, spec.DeclaredPosition, spec.MemberDefinition, spec.SpecialConstraint, spec.Variance, null) { |
---|
440 | BaseType = spec.BaseType, |
---|
441 | InterfacesDefined = spec.InterfacesDefined, |
---|
442 | TypeArguments = spec.TypeArguments |
---|
443 | }; |
---|
444 | } |
---|
445 | |
---|
446 | #region Properties |
---|
447 | |
---|
448 | public override AttributeTargets AttributeTargets { |
---|
449 | get { |
---|
450 | return AttributeTargets.GenericParameter; |
---|
451 | } |
---|
452 | } |
---|
453 | |
---|
454 | public Constraints Constraints { |
---|
455 | get { |
---|
456 | return constraints; |
---|
457 | } |
---|
458 | set { |
---|
459 | constraints = value; |
---|
460 | } |
---|
461 | } |
---|
462 | |
---|
463 | public IAssemblyDefinition DeclaringAssembly { |
---|
464 | get { |
---|
465 | return Module.DeclaringAssembly; |
---|
466 | } |
---|
467 | } |
---|
468 | |
---|
469 | public override string DocCommentHeader { |
---|
470 | get { |
---|
471 | throw new InvalidOperationException ( |
---|
472 | "Unexpected attempt to get doc comment from " + this.GetType ()); |
---|
473 | } |
---|
474 | } |
---|
475 | |
---|
476 | bool ITypeDefinition.IsComImport { |
---|
477 | get { |
---|
478 | return false; |
---|
479 | } |
---|
480 | } |
---|
481 | |
---|
482 | bool ITypeDefinition.IsPartial { |
---|
483 | get { |
---|
484 | return false; |
---|
485 | } |
---|
486 | } |
---|
487 | |
---|
488 | public bool IsMethodTypeParameter { |
---|
489 | get { |
---|
490 | return spec.IsMethodOwned; |
---|
491 | } |
---|
492 | } |
---|
493 | |
---|
494 | bool ITypeDefinition.IsTypeForwarder { |
---|
495 | get { |
---|
496 | return false; |
---|
497 | } |
---|
498 | } |
---|
499 | |
---|
500 | bool ITypeDefinition.IsCyclicTypeForwarder { |
---|
501 | get { |
---|
502 | return false; |
---|
503 | } |
---|
504 | } |
---|
505 | |
---|
506 | public string Name { |
---|
507 | get { |
---|
508 | return MemberName.Name; |
---|
509 | } |
---|
510 | } |
---|
511 | |
---|
512 | public string Namespace { |
---|
513 | get { |
---|
514 | return null; |
---|
515 | } |
---|
516 | } |
---|
517 | |
---|
518 | public TypeParameterSpec Type { |
---|
519 | get { |
---|
520 | return spec; |
---|
521 | } |
---|
522 | } |
---|
523 | |
---|
524 | public int TypeParametersCount { |
---|
525 | get { |
---|
526 | return 0; |
---|
527 | } |
---|
528 | } |
---|
529 | |
---|
530 | public TypeParameterSpec[] TypeParameters { |
---|
531 | get { |
---|
532 | return null; |
---|
533 | } |
---|
534 | } |
---|
535 | |
---|
536 | public override string[] ValidAttributeTargets { |
---|
537 | get { |
---|
538 | return attribute_target; |
---|
539 | } |
---|
540 | } |
---|
541 | |
---|
542 | public Variance Variance { |
---|
543 | get { |
---|
544 | return spec.Variance; |
---|
545 | } |
---|
546 | } |
---|
547 | |
---|
548 | public VarianceDecl VarianceDecl { get; private set; } |
---|
549 | |
---|
550 | #endregion |
---|
551 | |
---|
552 | // |
---|
553 | // This is called for each part of a partial generic type definition. |
---|
554 | // |
---|
555 | // If partial type parameters constraints are not null and we don't |
---|
556 | // already have constraints they become our constraints. If we already |
---|
557 | // have constraints, we must check that they're same. |
---|
558 | // |
---|
559 | public bool AddPartialConstraints (TypeDefinition part, TypeParameter tp) |
---|
560 | { |
---|
561 | if (builder == null) |
---|
562 | throw new InvalidOperationException (); |
---|
563 | |
---|
564 | var new_constraints = tp.constraints; |
---|
565 | if (new_constraints == null) |
---|
566 | return true; |
---|
567 | |
---|
568 | // TODO: could create spec only |
---|
569 | //tp.Define (null, -1, part.Definition); |
---|
570 | tp.spec.DeclaringType = part.Definition; |
---|
571 | if (!tp.ResolveConstraints (part)) |
---|
572 | return false; |
---|
573 | |
---|
574 | if (constraints != null) |
---|
575 | return spec.HasSameConstraintsDefinition (tp.Type); |
---|
576 | |
---|
577 | // Copy constraint from resolved part to partial container |
---|
578 | spec.SpecialConstraint = tp.spec.SpecialConstraint; |
---|
579 | spec.InterfacesDefined = tp.spec.InterfacesDefined; |
---|
580 | spec.TypeArguments = tp.spec.TypeArguments; |
---|
581 | spec.BaseType = tp.spec.BaseType; |
---|
582 | |
---|
583 | return true; |
---|
584 | } |
---|
585 | |
---|
586 | public override void ApplyAttributeBuilder (Attribute a, MethodSpec ctor, byte[] cdata, PredefinedAttributes pa) |
---|
587 | { |
---|
588 | builder.SetCustomAttribute ((ConstructorInfo) ctor.GetMetaInfo (), cdata); |
---|
589 | } |
---|
590 | |
---|
591 | public void CheckGenericConstraints (bool obsoleteCheck) |
---|
592 | { |
---|
593 | if (constraints != null) |
---|
594 | constraints.CheckGenericConstraints (this, obsoleteCheck); |
---|
595 | } |
---|
596 | |
---|
597 | public TypeParameter CreateHoistedCopy (TypeSpec declaringSpec) |
---|
598 | { |
---|
599 | return new TypeParameter (spec, declaringSpec, MemberName, null); |
---|
600 | } |
---|
601 | |
---|
602 | public override bool Define () |
---|
603 | { |
---|
604 | return true; |
---|
605 | } |
---|
606 | |
---|
607 | // |
---|
608 | // This is the first method which is called during the resolving |
---|
609 | // process; we're called immediately after creating the type parameters |
---|
610 | // with SRE (by calling `DefineGenericParameters()' on the TypeBuilder / |
---|
611 | // MethodBuilder). |
---|
612 | // |
---|
613 | public void Create (TypeSpec declaringType, TypeContainer parent) |
---|
614 | { |
---|
615 | if (builder != null) |
---|
616 | throw new InternalErrorException (); |
---|
617 | |
---|
618 | // Needed to get compiler reference |
---|
619 | this.Parent = parent; |
---|
620 | spec.DeclaringType = declaringType; |
---|
621 | } |
---|
622 | |
---|
623 | public void Define (GenericTypeParameterBuilder type) |
---|
624 | { |
---|
625 | this.builder = type; |
---|
626 | spec.SetMetaInfo (type); |
---|
627 | } |
---|
628 | |
---|
629 | public void Define (TypeParameter tp) |
---|
630 | { |
---|
631 | builder = tp.builder; |
---|
632 | } |
---|
633 | |
---|
634 | public void EmitConstraints (GenericTypeParameterBuilder builder) |
---|
635 | { |
---|
636 | var attr = GenericParameterAttributes.None; |
---|
637 | if (spec.Variance == Variance.Contravariant) |
---|
638 | attr |= GenericParameterAttributes.Contravariant; |
---|
639 | else if (spec.Variance == Variance.Covariant) |
---|
640 | attr |= GenericParameterAttributes.Covariant; |
---|
641 | |
---|
642 | if (spec.HasSpecialClass) |
---|
643 | attr |= GenericParameterAttributes.ReferenceTypeConstraint; |
---|
644 | else if (spec.HasSpecialStruct) |
---|
645 | attr |= GenericParameterAttributes.NotNullableValueTypeConstraint | GenericParameterAttributes.DefaultConstructorConstraint; |
---|
646 | |
---|
647 | if (spec.HasSpecialConstructor) |
---|
648 | attr |= GenericParameterAttributes.DefaultConstructorConstraint; |
---|
649 | |
---|
650 | if (spec.BaseType.BuiltinType != BuiltinTypeSpec.Type.Object) |
---|
651 | builder.SetBaseTypeConstraint (spec.BaseType.GetMetaInfo ()); |
---|
652 | |
---|
653 | if (spec.InterfacesDefined != null) |
---|
654 | builder.SetInterfaceConstraints (spec.InterfacesDefined.Select (l => l.GetMetaInfo ()).ToArray ()); |
---|
655 | |
---|
656 | if (spec.TypeArguments != null) { |
---|
657 | var meta_constraints = new List<MetaType> (spec.TypeArguments.Length); |
---|
658 | foreach (var c in spec.TypeArguments) { |
---|
659 | // |
---|
660 | // Inflated type parameters can collide with special constraint types, don't |
---|
661 | // emit any such type parameter. |
---|
662 | // |
---|
663 | if (c.BuiltinType == BuiltinTypeSpec.Type.Object || c.BuiltinType == BuiltinTypeSpec.Type.ValueType) |
---|
664 | continue; |
---|
665 | |
---|
666 | meta_constraints.Add (c.GetMetaInfo ()); |
---|
667 | } |
---|
668 | |
---|
669 | builder.SetInterfaceConstraints (meta_constraints.ToArray ()); |
---|
670 | } |
---|
671 | |
---|
672 | builder.SetGenericParameterAttributes (attr); |
---|
673 | } |
---|
674 | |
---|
675 | public override void Emit () |
---|
676 | { |
---|
677 | EmitConstraints (builder); |
---|
678 | |
---|
679 | if (OptAttributes != null) |
---|
680 | OptAttributes.Emit (); |
---|
681 | |
---|
682 | base.Emit (); |
---|
683 | } |
---|
684 | |
---|
685 | public void ErrorInvalidVariance (IMemberContext mc, Variance expected) |
---|
686 | { |
---|
687 | Report.SymbolRelatedToPreviousError (mc.CurrentMemberDefinition); |
---|
688 | string input_variance = Variance == Variance.Contravariant ? "contravariant" : "covariant"; |
---|
689 | string gtype_variance; |
---|
690 | switch (expected) { |
---|
691 | case Variance.Contravariant: gtype_variance = "contravariantly"; break; |
---|
692 | case Variance.Covariant: gtype_variance = "covariantly"; break; |
---|
693 | default: gtype_variance = "invariantly"; break; |
---|
694 | } |
---|
695 | |
---|
696 | Delegate d = mc as Delegate; |
---|
697 | string parameters = d != null ? d.Parameters.GetSignatureForError () : ""; |
---|
698 | |
---|
699 | Report.Error (1961, Location, |
---|
700 | "The {2} type parameter `{0}' must be {3} valid on `{1}{4}'", |
---|
701 | GetSignatureForError (), mc.GetSignatureForError (), input_variance, gtype_variance, parameters); |
---|
702 | } |
---|
703 | |
---|
704 | public TypeSpec GetAttributeCoClass () |
---|
705 | { |
---|
706 | return null; |
---|
707 | } |
---|
708 | |
---|
709 | public string GetAttributeDefaultMember () |
---|
710 | { |
---|
711 | throw new NotSupportedException (); |
---|
712 | } |
---|
713 | |
---|
714 | public AttributeUsageAttribute GetAttributeUsage (PredefinedAttribute pa) |
---|
715 | { |
---|
716 | throw new NotSupportedException (); |
---|
717 | } |
---|
718 | |
---|
719 | public override string GetSignatureForDocumentation () |
---|
720 | { |
---|
721 | throw new NotImplementedException (); |
---|
722 | } |
---|
723 | |
---|
724 | public override string GetSignatureForError () |
---|
725 | { |
---|
726 | return MemberName.Name; |
---|
727 | } |
---|
728 | |
---|
729 | bool ITypeDefinition.IsInternalAsPublic (IAssemblyDefinition assembly) |
---|
730 | { |
---|
731 | return spec.MemberDefinition.DeclaringAssembly == assembly; |
---|
732 | } |
---|
733 | |
---|
734 | public void LoadMembers (TypeSpec declaringType, bool onlyTypes, ref MemberCache cache) |
---|
735 | { |
---|
736 | throw new NotSupportedException ("Not supported for compiled definition"); |
---|
737 | } |
---|
738 | |
---|
739 | // |
---|
740 | // Resolves all type parameter constraints |
---|
741 | // |
---|
742 | public bool ResolveConstraints (IMemberContext context) |
---|
743 | { |
---|
744 | if (constraints != null) |
---|
745 | return constraints.Resolve (context, this); |
---|
746 | |
---|
747 | if (spec.BaseType == null) |
---|
748 | spec.BaseType = context.Module.Compiler.BuiltinTypes.Object; |
---|
749 | |
---|
750 | return true; |
---|
751 | } |
---|
752 | |
---|
753 | public override bool IsClsComplianceRequired () |
---|
754 | { |
---|
755 | return false; |
---|
756 | } |
---|
757 | |
---|
758 | public new void VerifyClsCompliance () |
---|
759 | { |
---|
760 | if (constraints != null) |
---|
761 | constraints.VerifyClsCompliance (Report); |
---|
762 | } |
---|
763 | |
---|
764 | public void WarningParentNameConflict (TypeParameter conflict) |
---|
765 | { |
---|
766 | conflict.Report.SymbolRelatedToPreviousError (conflict.Location, null); |
---|
767 | conflict.Report.Warning (693, 3, Location, |
---|
768 | "Type parameter `{0}' has the same name as the type parameter from outer type `{1}'", |
---|
769 | GetSignatureForError (), conflict.CurrentType.GetSignatureForError ()); |
---|
770 | } |
---|
771 | } |
---|
772 | |
---|
773 | [System.Diagnostics.DebuggerDisplay ("{DisplayDebugInfo()}")] |
---|
774 | public class TypeParameterSpec : TypeSpec |
---|
775 | { |
---|
776 | public static readonly new TypeParameterSpec[] EmptyTypes = new TypeParameterSpec[0]; |
---|
777 | |
---|
778 | Variance variance; |
---|
779 | SpecialConstraint spec; |
---|
780 | int tp_pos; |
---|
781 | TypeSpec[] targs; |
---|
782 | TypeSpec[] ifaces_defined; |
---|
783 | TypeSpec effective_base; |
---|
784 | |
---|
785 | // |
---|
786 | // Creates type owned type parameter |
---|
787 | // |
---|
788 | public TypeParameterSpec (TypeSpec declaringType, int index, ITypeDefinition definition, SpecialConstraint spec, Variance variance, MetaType info) |
---|
789 | : base (MemberKind.TypeParameter, declaringType, definition, info, Modifiers.PUBLIC) |
---|
790 | { |
---|
791 | this.variance = variance; |
---|
792 | this.spec = spec; |
---|
793 | state &= ~StateFlags.Obsolete_Undetected; |
---|
794 | tp_pos = index; |
---|
795 | } |
---|
796 | |
---|
797 | // |
---|
798 | // Creates method owned type parameter |
---|
799 | // |
---|
800 | public TypeParameterSpec (int index, ITypeDefinition definition, SpecialConstraint spec, Variance variance, MetaType info) |
---|
801 | : this (null, index, definition, spec, variance, info) |
---|
802 | { |
---|
803 | } |
---|
804 | |
---|
805 | #region Properties |
---|
806 | |
---|
807 | public int DeclaredPosition { |
---|
808 | get { |
---|
809 | return tp_pos; |
---|
810 | } |
---|
811 | set { |
---|
812 | tp_pos = value; |
---|
813 | } |
---|
814 | } |
---|
815 | |
---|
816 | public bool HasSpecialConstructor { |
---|
817 | get { |
---|
818 | return (spec & SpecialConstraint.Constructor) != 0; |
---|
819 | } |
---|
820 | } |
---|
821 | |
---|
822 | public bool HasSpecialClass { |
---|
823 | get { |
---|
824 | return (spec & SpecialConstraint.Class) != 0; |
---|
825 | } |
---|
826 | } |
---|
827 | |
---|
828 | public bool HasSpecialStruct { |
---|
829 | get { |
---|
830 | return (spec & SpecialConstraint.Struct) != 0; |
---|
831 | } |
---|
832 | } |
---|
833 | |
---|
834 | public bool HasAnyTypeConstraint { |
---|
835 | get { |
---|
836 | return (spec & (SpecialConstraint.Class | SpecialConstraint.Struct)) != 0 || ifaces != null || targs != null || HasTypeConstraint; |
---|
837 | } |
---|
838 | } |
---|
839 | |
---|
840 | public bool HasTypeConstraint { |
---|
841 | get { |
---|
842 | var bt = BaseType.BuiltinType; |
---|
843 | return bt != BuiltinTypeSpec.Type.Object && bt != BuiltinTypeSpec.Type.ValueType; |
---|
844 | } |
---|
845 | } |
---|
846 | |
---|
847 | public override IList<TypeSpec> Interfaces { |
---|
848 | get { |
---|
849 | if ((state & StateFlags.InterfacesExpanded) == 0) { |
---|
850 | if (ifaces != null) { |
---|
851 | if (ifaces_defined == null) |
---|
852 | ifaces_defined = ifaces.ToArray (); |
---|
853 | |
---|
854 | for (int i = 0; i < ifaces_defined.Length; ++i ) { |
---|
855 | var iface_type = ifaces_defined[i]; |
---|
856 | var td = iface_type.MemberDefinition as TypeDefinition; |
---|
857 | if (td != null) |
---|
858 | td.DoExpandBaseInterfaces (); |
---|
859 | |
---|
860 | if (iface_type.Interfaces != null) { |
---|
861 | for (int ii = 0; ii < iface_type.Interfaces.Count; ++ii) { |
---|
862 | var ii_iface_type = iface_type.Interfaces [ii]; |
---|
863 | AddInterface (ii_iface_type); |
---|
864 | } |
---|
865 | } |
---|
866 | } |
---|
867 | } else if (ifaces_defined == null) { |
---|
868 | ifaces_defined = ifaces == null ? TypeSpec.EmptyTypes : ifaces.ToArray (); |
---|
869 | } |
---|
870 | |
---|
871 | // |
---|
872 | // Include all base type interfaces too, see ImportTypeBase for details |
---|
873 | // |
---|
874 | if (BaseType != null) { |
---|
875 | var td = BaseType.MemberDefinition as TypeDefinition; |
---|
876 | if (td != null) |
---|
877 | td.DoExpandBaseInterfaces (); |
---|
878 | |
---|
879 | if (BaseType.Interfaces != null) { |
---|
880 | foreach (var iface in BaseType.Interfaces) { |
---|
881 | AddInterface (iface); |
---|
882 | } |
---|
883 | } |
---|
884 | } |
---|
885 | |
---|
886 | state |= StateFlags.InterfacesExpanded; |
---|
887 | } |
---|
888 | |
---|
889 | return ifaces; |
---|
890 | } |
---|
891 | } |
---|
892 | |
---|
893 | // |
---|
894 | // Unexpanded interfaces list |
---|
895 | // |
---|
896 | public TypeSpec[] InterfacesDefined { |
---|
897 | get { |
---|
898 | if (ifaces_defined == null) { |
---|
899 | ifaces_defined = ifaces == null ? TypeSpec.EmptyTypes : ifaces.ToArray (); |
---|
900 | } |
---|
901 | |
---|
902 | return ifaces_defined.Length == 0 ? null : ifaces_defined; |
---|
903 | } |
---|
904 | set { |
---|
905 | ifaces_defined = value; |
---|
906 | if (value != null && value.Length != 0) |
---|
907 | ifaces = new List<TypeSpec> (value); |
---|
908 | } |
---|
909 | } |
---|
910 | |
---|
911 | public bool IsConstrained { |
---|
912 | get { |
---|
913 | return spec != SpecialConstraint.None || ifaces != null || targs != null || HasTypeConstraint; |
---|
914 | } |
---|
915 | } |
---|
916 | |
---|
917 | // |
---|
918 | // Returns whether the type parameter is known to be a reference type |
---|
919 | // |
---|
920 | public new bool IsReferenceType { |
---|
921 | get { |
---|
922 | if ((spec & (SpecialConstraint.Class | SpecialConstraint.Struct)) != 0) |
---|
923 | return (spec & SpecialConstraint.Class) != 0; |
---|
924 | |
---|
925 | // |
---|
926 | // Full check is needed (see IsValueType for details) |
---|
927 | // |
---|
928 | if (HasTypeConstraint && TypeSpec.IsReferenceType (BaseType)) |
---|
929 | return true; |
---|
930 | |
---|
931 | if (targs != null) { |
---|
932 | foreach (var ta in targs) { |
---|
933 | // |
---|
934 | // Secondary special constraints are ignored (I am not sure why) |
---|
935 | // |
---|
936 | var tp = ta as TypeParameterSpec; |
---|
937 | if (tp != null && (tp.spec & (SpecialConstraint.Class | SpecialConstraint.Struct)) != 0) |
---|
938 | continue; |
---|
939 | |
---|
940 | if (TypeSpec.IsReferenceType (ta)) |
---|
941 | return true; |
---|
942 | } |
---|
943 | } |
---|
944 | |
---|
945 | return false; |
---|
946 | } |
---|
947 | } |
---|
948 | |
---|
949 | // |
---|
950 | // Returns whether the type parameter is known to be a value type |
---|
951 | // |
---|
952 | public new bool IsValueType { |
---|
953 | get { |
---|
954 | // |
---|
955 | // Even if structs/enums cannot be used directly as constraints |
---|
956 | // they can apear as constraint type when inheriting base constraint |
---|
957 | // which has dependant type parameter constraint which has been |
---|
958 | // inflated using value type |
---|
959 | // |
---|
960 | // class A : B<int> { override void Foo<U> () {} } |
---|
961 | // class B<T> { virtual void Foo<U> () where U : T {} } |
---|
962 | // |
---|
963 | if (HasSpecialStruct) |
---|
964 | return true; |
---|
965 | |
---|
966 | if (targs != null) { |
---|
967 | foreach (var ta in targs) { |
---|
968 | if (TypeSpec.IsValueType (ta)) |
---|
969 | return true; |
---|
970 | } |
---|
971 | } |
---|
972 | |
---|
973 | return false; |
---|
974 | } |
---|
975 | } |
---|
976 | |
---|
977 | public override string Name { |
---|
978 | get { |
---|
979 | return definition.Name; |
---|
980 | } |
---|
981 | } |
---|
982 | |
---|
983 | public bool IsMethodOwned { |
---|
984 | get { |
---|
985 | return DeclaringType == null; |
---|
986 | } |
---|
987 | } |
---|
988 | |
---|
989 | public SpecialConstraint SpecialConstraint { |
---|
990 | get { |
---|
991 | return spec; |
---|
992 | } |
---|
993 | set { |
---|
994 | spec = value; |
---|
995 | } |
---|
996 | } |
---|
997 | |
---|
998 | // |
---|
999 | // Types used to inflate the generic type |
---|
1000 | // |
---|
1001 | public new TypeSpec[] TypeArguments { |
---|
1002 | get { |
---|
1003 | return targs; |
---|
1004 | } |
---|
1005 | set { |
---|
1006 | targs = value; |
---|
1007 | } |
---|
1008 | } |
---|
1009 | |
---|
1010 | public Variance Variance { |
---|
1011 | get { |
---|
1012 | return variance; |
---|
1013 | } |
---|
1014 | } |
---|
1015 | |
---|
1016 | #endregion |
---|
1017 | |
---|
1018 | public string DisplayDebugInfo () |
---|
1019 | { |
---|
1020 | var s = GetSignatureForError (); |
---|
1021 | return IsMethodOwned ? s + "!!" : s + "!"; |
---|
1022 | } |
---|
1023 | |
---|
1024 | // |
---|
1025 | // Finds effective base class. The effective base class is always a class-type |
---|
1026 | // |
---|
1027 | public TypeSpec GetEffectiveBase () |
---|
1028 | { |
---|
1029 | if (HasSpecialStruct) |
---|
1030 | return BaseType; |
---|
1031 | |
---|
1032 | // |
---|
1033 | // If T has a class-type constraint C but no type-parameter constraints, its effective base class is C |
---|
1034 | // |
---|
1035 | if (BaseType != null && targs == null) { |
---|
1036 | // |
---|
1037 | // If T has a constraint V that is a value-type, use instead the most specific base type of V that is a class-type. |
---|
1038 | // |
---|
1039 | // LAMESPEC: Is System.ValueType always the most specific base type in this case? |
---|
1040 | // |
---|
1041 | // Note: This can never happen in an explicitly given constraint, but may occur when the constraints of a generic method |
---|
1042 | // are implicitly inherited by an overriding method declaration or an explicit implementation of an interface method. |
---|
1043 | // |
---|
1044 | return BaseType.IsStruct ? BaseType.BaseType : BaseType; |
---|
1045 | } |
---|
1046 | |
---|
1047 | if (effective_base != null) |
---|
1048 | return effective_base; |
---|
1049 | |
---|
1050 | var types = new TypeSpec [HasTypeConstraint ? targs.Length + 1 : targs.Length]; |
---|
1051 | |
---|
1052 | for (int i = 0; i < targs.Length; ++i) { |
---|
1053 | var t = targs [i]; |
---|
1054 | |
---|
1055 | // Same issue as above, inherited constraints can be of struct type |
---|
1056 | if (t.IsStruct) { |
---|
1057 | types [i] = t.BaseType; |
---|
1058 | continue; |
---|
1059 | } |
---|
1060 | |
---|
1061 | var tps = t as TypeParameterSpec; |
---|
1062 | types [i] = tps != null ? tps.GetEffectiveBase () : t; |
---|
1063 | } |
---|
1064 | |
---|
1065 | if (HasTypeConstraint) |
---|
1066 | types [types.Length - 1] = BaseType; |
---|
1067 | |
---|
1068 | return effective_base = Convert.FindMostEncompassedType (types); |
---|
1069 | } |
---|
1070 | |
---|
1071 | public override string GetSignatureForDocumentation () |
---|
1072 | { |
---|
1073 | var prefix = IsMethodOwned ? "``" : "`"; |
---|
1074 | return prefix + DeclaredPosition; |
---|
1075 | } |
---|
1076 | |
---|
1077 | public override string GetSignatureForError () |
---|
1078 | { |
---|
1079 | return Name; |
---|
1080 | } |
---|
1081 | |
---|
1082 | // |
---|
1083 | // Constraints have to match by definition but not position, used by |
---|
1084 | // partial classes or methods |
---|
1085 | // |
---|
1086 | public bool HasSameConstraintsDefinition (TypeParameterSpec other) |
---|
1087 | { |
---|
1088 | if (spec != other.spec) |
---|
1089 | return false; |
---|
1090 | |
---|
1091 | if (BaseType != other.BaseType) |
---|
1092 | return false; |
---|
1093 | |
---|
1094 | if (!TypeSpecComparer.Override.IsSame (InterfacesDefined, other.InterfacesDefined)) |
---|
1095 | return false; |
---|
1096 | |
---|
1097 | if (!TypeSpecComparer.Override.IsSame (targs, other.targs)) |
---|
1098 | return false; |
---|
1099 | |
---|
1100 | return true; |
---|
1101 | } |
---|
1102 | |
---|
1103 | // |
---|
1104 | // Constraints have to match by using same set of types, used by |
---|
1105 | // implicit interface implementation |
---|
1106 | // |
---|
1107 | public bool HasSameConstraintsImplementation (TypeParameterSpec other) |
---|
1108 | { |
---|
1109 | if (spec != other.spec) |
---|
1110 | return false; |
---|
1111 | |
---|
1112 | // |
---|
1113 | // It can be same base type or inflated type parameter |
---|
1114 | // |
---|
1115 | // interface I<T> { void Foo<U> where U : T; } |
---|
1116 | // class A : I<int> { void Foo<X> where X : int {} } |
---|
1117 | // |
---|
1118 | bool found; |
---|
1119 | if (!TypeSpecComparer.Override.IsEqual (BaseType, other.BaseType)) { |
---|
1120 | if (other.targs == null) |
---|
1121 | return false; |
---|
1122 | |
---|
1123 | found = false; |
---|
1124 | foreach (var otarg in other.targs) { |
---|
1125 | if (TypeSpecComparer.Override.IsEqual (BaseType, otarg)) { |
---|
1126 | found = true; |
---|
1127 | break; |
---|
1128 | } |
---|
1129 | } |
---|
1130 | |
---|
1131 | if (!found) |
---|
1132 | return false; |
---|
1133 | } |
---|
1134 | |
---|
1135 | // Check interfaces implementation -> definition |
---|
1136 | if (InterfacesDefined != null) { |
---|
1137 | // |
---|
1138 | // Iterate over inflated interfaces |
---|
1139 | // |
---|
1140 | foreach (var iface in Interfaces) { |
---|
1141 | found = false; |
---|
1142 | if (other.InterfacesDefined != null) { |
---|
1143 | foreach (var oiface in other.Interfaces) { |
---|
1144 | if (TypeSpecComparer.Override.IsEqual (iface, oiface)) { |
---|
1145 | found = true; |
---|
1146 | break; |
---|
1147 | } |
---|
1148 | } |
---|
1149 | } |
---|
1150 | |
---|
1151 | if (found) |
---|
1152 | continue; |
---|
1153 | |
---|
1154 | if (other.targs != null) { |
---|
1155 | foreach (var otarg in other.targs) { |
---|
1156 | if (TypeSpecComparer.Override.IsEqual (iface, otarg)) { |
---|
1157 | found = true; |
---|
1158 | break; |
---|
1159 | } |
---|
1160 | } |
---|
1161 | } |
---|
1162 | |
---|
1163 | if (!found) |
---|
1164 | return false; |
---|
1165 | } |
---|
1166 | } |
---|
1167 | |
---|
1168 | // Check interfaces implementation <- definition |
---|
1169 | if (other.InterfacesDefined != null) { |
---|
1170 | if (InterfacesDefined == null) |
---|
1171 | return false; |
---|
1172 | |
---|
1173 | // |
---|
1174 | // Iterate over inflated interfaces |
---|
1175 | // |
---|
1176 | foreach (var oiface in other.Interfaces) { |
---|
1177 | found = false; |
---|
1178 | foreach (var iface in Interfaces) { |
---|
1179 | if (TypeSpecComparer.Override.IsEqual (iface, oiface)) { |
---|
1180 | found = true; |
---|
1181 | break; |
---|
1182 | } |
---|
1183 | } |
---|
1184 | |
---|
1185 | if (!found) |
---|
1186 | return false; |
---|
1187 | } |
---|
1188 | } |
---|
1189 | |
---|
1190 | // Check type parameters implementation -> definition |
---|
1191 | if (targs != null) { |
---|
1192 | if (other.targs == null) |
---|
1193 | return false; |
---|
1194 | |
---|
1195 | foreach (var targ in targs) { |
---|
1196 | found = false; |
---|
1197 | foreach (var otarg in other.targs) { |
---|
1198 | if (TypeSpecComparer.Override.IsEqual (targ, otarg)) { |
---|
1199 | found = true; |
---|
1200 | break; |
---|
1201 | } |
---|
1202 | } |
---|
1203 | |
---|
1204 | if (!found) |
---|
1205 | return false; |
---|
1206 | } |
---|
1207 | } |
---|
1208 | |
---|
1209 | // Check type parameters implementation <- definition |
---|
1210 | if (other.targs != null) { |
---|
1211 | foreach (var otarg in other.targs) { |
---|
1212 | // Ignore inflated type arguments, were checked above |
---|
1213 | if (!otarg.IsGenericParameter) |
---|
1214 | continue; |
---|
1215 | |
---|
1216 | if (targs == null) |
---|
1217 | return false; |
---|
1218 | |
---|
1219 | found = false; |
---|
1220 | foreach (var targ in targs) { |
---|
1221 | if (TypeSpecComparer.Override.IsEqual (targ, otarg)) { |
---|
1222 | found = true; |
---|
1223 | break; |
---|
1224 | } |
---|
1225 | } |
---|
1226 | |
---|
1227 | if (!found) |
---|
1228 | return false; |
---|
1229 | } |
---|
1230 | } |
---|
1231 | |
---|
1232 | return true; |
---|
1233 | } |
---|
1234 | |
---|
1235 | public static TypeParameterSpec[] InflateConstraints (TypeParameterInflator inflator, TypeParameterSpec[] tparams) |
---|
1236 | { |
---|
1237 | return InflateConstraints (tparams, l => l, inflator); |
---|
1238 | } |
---|
1239 | |
---|
1240 | public static TypeParameterSpec[] InflateConstraints<T> (TypeParameterSpec[] tparams, Func<T, TypeParameterInflator> inflatorFactory, T arg) |
---|
1241 | { |
---|
1242 | TypeParameterSpec[] constraints = null; |
---|
1243 | TypeParameterInflator? inflator = null; |
---|
1244 | |
---|
1245 | for (int i = 0; i < tparams.Length; ++i) { |
---|
1246 | var tp = tparams[i]; |
---|
1247 | if (tp.HasTypeConstraint || tp.InterfacesDefined != null || tp.TypeArguments != null) { |
---|
1248 | if (constraints == null) { |
---|
1249 | constraints = new TypeParameterSpec[tparams.Length]; |
---|
1250 | Array.Copy (tparams, constraints, constraints.Length); |
---|
1251 | } |
---|
1252 | |
---|
1253 | // |
---|
1254 | // Using a factory to avoid possibly expensive inflator build up |
---|
1255 | // |
---|
1256 | if (inflator == null) |
---|
1257 | inflator = inflatorFactory (arg); |
---|
1258 | |
---|
1259 | constraints[i] = (TypeParameterSpec) constraints[i].InflateMember (inflator.Value); |
---|
1260 | } |
---|
1261 | } |
---|
1262 | |
---|
1263 | if (constraints == null) |
---|
1264 | constraints = tparams; |
---|
1265 | |
---|
1266 | return constraints; |
---|
1267 | } |
---|
1268 | |
---|
1269 | public void InflateConstraints (TypeParameterInflator inflator, TypeParameterSpec tps) |
---|
1270 | { |
---|
1271 | tps.BaseType = inflator.Inflate (BaseType); |
---|
1272 | |
---|
1273 | var defined = InterfacesDefined; |
---|
1274 | if (defined != null) { |
---|
1275 | tps.ifaces_defined = new TypeSpec[defined.Length]; |
---|
1276 | for (int i = 0; i < defined.Length; ++i) |
---|
1277 | tps.ifaces_defined [i] = inflator.Inflate (defined[i]); |
---|
1278 | } else if (ifaces_defined == TypeSpec.EmptyTypes) { |
---|
1279 | tps.ifaces_defined = TypeSpec.EmptyTypes; |
---|
1280 | } |
---|
1281 | |
---|
1282 | var ifaces = Interfaces; |
---|
1283 | if (ifaces != null) { |
---|
1284 | tps.ifaces = new List<TypeSpec> (ifaces.Count); |
---|
1285 | for (int i = 0; i < ifaces.Count; ++i) |
---|
1286 | tps.ifaces.Add (inflator.Inflate (ifaces[i])); |
---|
1287 | tps.state |= StateFlags.InterfacesExpanded; |
---|
1288 | } |
---|
1289 | |
---|
1290 | if (targs != null) { |
---|
1291 | tps.targs = new TypeSpec[targs.Length]; |
---|
1292 | for (int i = 0; i < targs.Length; ++i) |
---|
1293 | tps.targs[i] = inflator.Inflate (targs[i]); |
---|
1294 | } |
---|
1295 | } |
---|
1296 | |
---|
1297 | public override MemberSpec InflateMember (TypeParameterInflator inflator) |
---|
1298 | { |
---|
1299 | var tps = (TypeParameterSpec) MemberwiseClone (); |
---|
1300 | #if DEBUG |
---|
1301 | tps.ID += 1000000; |
---|
1302 | #endif |
---|
1303 | |
---|
1304 | InflateConstraints (inflator, tps); |
---|
1305 | return tps; |
---|
1306 | } |
---|
1307 | |
---|
1308 | // |
---|
1309 | // Populates type parameter members using type parameter constraints |
---|
1310 | // The trick here is to be called late enough but not too late to |
---|
1311 | // populate member cache with all members from other types |
---|
1312 | // |
---|
1313 | protected override void InitializeMemberCache (bool onlyTypes) |
---|
1314 | { |
---|
1315 | cache = new MemberCache (); |
---|
1316 | |
---|
1317 | // |
---|
1318 | // For a type parameter the membercache is the union of the sets of members of the types |
---|
1319 | // specified as a primary constraint or secondary constraint |
---|
1320 | // |
---|
1321 | if (BaseType.BuiltinType != BuiltinTypeSpec.Type.Object && BaseType.BuiltinType != BuiltinTypeSpec.Type.ValueType) |
---|
1322 | cache.AddBaseType (BaseType); |
---|
1323 | |
---|
1324 | if (InterfacesDefined != null) { |
---|
1325 | foreach (var iface_type in InterfacesDefined) { |
---|
1326 | cache.AddInterface (iface_type); |
---|
1327 | } |
---|
1328 | } |
---|
1329 | |
---|
1330 | if (targs != null) { |
---|
1331 | foreach (var ta in targs) { |
---|
1332 | var tps = ta as TypeParameterSpec; |
---|
1333 | IList<TypeSpec> ifaces; |
---|
1334 | if (tps != null) { |
---|
1335 | var b_type = tps.GetEffectiveBase (); |
---|
1336 | if (b_type != null && b_type.BuiltinType != BuiltinTypeSpec.Type.Object && b_type.BuiltinType != BuiltinTypeSpec.Type.ValueType) |
---|
1337 | cache.AddBaseType (b_type); |
---|
1338 | |
---|
1339 | ifaces = tps.InterfacesDefined; |
---|
1340 | } else { |
---|
1341 | ifaces = ta.Interfaces; |
---|
1342 | } |
---|
1343 | |
---|
1344 | if (ifaces != null) { |
---|
1345 | foreach (var iface_type in ifaces) { |
---|
1346 | cache.AddInterface (iface_type); |
---|
1347 | } |
---|
1348 | } |
---|
1349 | } |
---|
1350 | } |
---|
1351 | } |
---|
1352 | |
---|
1353 | public bool IsConvertibleToInterface (TypeSpec iface) |
---|
1354 | { |
---|
1355 | if (Interfaces != null) { |
---|
1356 | foreach (var t in Interfaces) { |
---|
1357 | if (t == iface) |
---|
1358 | return true; |
---|
1359 | } |
---|
1360 | } |
---|
1361 | |
---|
1362 | if (TypeArguments != null) { |
---|
1363 | foreach (var t in TypeArguments) { |
---|
1364 | var tps = t as TypeParameterSpec; |
---|
1365 | if (tps != null) { |
---|
1366 | if (tps.IsConvertibleToInterface (iface)) |
---|
1367 | return true; |
---|
1368 | |
---|
1369 | continue; |
---|
1370 | } |
---|
1371 | |
---|
1372 | if (t.ImplementsInterface (iface, false)) |
---|
1373 | return true; |
---|
1374 | } |
---|
1375 | } |
---|
1376 | |
---|
1377 | return false; |
---|
1378 | } |
---|
1379 | |
---|
1380 | public static bool HasAnyTypeParameterTypeConstrained (IGenericMethodDefinition md) |
---|
1381 | { |
---|
1382 | var tps = md.TypeParameters; |
---|
1383 | for (int i = 0; i < md.TypeParametersCount; ++i) { |
---|
1384 | if (tps[i].HasAnyTypeConstraint) { |
---|
1385 | return true; |
---|
1386 | } |
---|
1387 | } |
---|
1388 | |
---|
1389 | return false; |
---|
1390 | } |
---|
1391 | |
---|
1392 | public static bool HasAnyTypeParameterConstrained (IGenericMethodDefinition md) |
---|
1393 | { |
---|
1394 | var tps = md.TypeParameters; |
---|
1395 | for (int i = 0; i < md.TypeParametersCount; ++i) { |
---|
1396 | if (tps[i].IsConstrained) { |
---|
1397 | return true; |
---|
1398 | } |
---|
1399 | } |
---|
1400 | |
---|
1401 | return false; |
---|
1402 | } |
---|
1403 | |
---|
1404 | public bool HasDependencyOn (TypeSpec type) |
---|
1405 | { |
---|
1406 | if (TypeArguments != null) { |
---|
1407 | foreach (var targ in TypeArguments) { |
---|
1408 | if (TypeSpecComparer.Override.IsEqual (targ, type)) |
---|
1409 | return true; |
---|
1410 | |
---|
1411 | var tps = targ as TypeParameterSpec; |
---|
1412 | if (tps != null && tps.HasDependencyOn (type)) |
---|
1413 | return true; |
---|
1414 | } |
---|
1415 | } |
---|
1416 | |
---|
1417 | return false; |
---|
1418 | } |
---|
1419 | |
---|
1420 | public override TypeSpec Mutate (TypeParameterMutator mutator) |
---|
1421 | { |
---|
1422 | return mutator.Mutate (this); |
---|
1423 | } |
---|
1424 | } |
---|
1425 | |
---|
1426 | public struct TypeParameterInflator |
---|
1427 | { |
---|
1428 | readonly TypeSpec type; |
---|
1429 | readonly TypeParameterSpec[] tparams; |
---|
1430 | readonly TypeSpec[] targs; |
---|
1431 | readonly IModuleContext context; |
---|
1432 | |
---|
1433 | public TypeParameterInflator (TypeParameterInflator nested, TypeSpec type) |
---|
1434 | : this (nested.context, type, nested.tparams, nested.targs) |
---|
1435 | { |
---|
1436 | } |
---|
1437 | |
---|
1438 | public TypeParameterInflator (IModuleContext context, TypeSpec type, TypeParameterSpec[] tparams, TypeSpec[] targs) |
---|
1439 | { |
---|
1440 | if (tparams.Length != targs.Length) |
---|
1441 | throw new ArgumentException ("Invalid arguments"); |
---|
1442 | |
---|
1443 | this.context = context; |
---|
1444 | this.tparams = tparams; |
---|
1445 | this.targs = targs; |
---|
1446 | this.type = type; |
---|
1447 | } |
---|
1448 | |
---|
1449 | #region Properties |
---|
1450 | |
---|
1451 | public IModuleContext Context { |
---|
1452 | get { |
---|
1453 | return context; |
---|
1454 | } |
---|
1455 | } |
---|
1456 | |
---|
1457 | public TypeSpec TypeInstance { |
---|
1458 | get { |
---|
1459 | return type; |
---|
1460 | } |
---|
1461 | } |
---|
1462 | |
---|
1463 | // |
---|
1464 | // Type parameters to inflate |
---|
1465 | // |
---|
1466 | public TypeParameterSpec[] TypeParameters { |
---|
1467 | get { |
---|
1468 | return tparams; |
---|
1469 | } |
---|
1470 | } |
---|
1471 | |
---|
1472 | #endregion |
---|
1473 | |
---|
1474 | public TypeSpec Inflate (TypeSpec type) |
---|
1475 | { |
---|
1476 | var tp = type as TypeParameterSpec; |
---|
1477 | if (tp != null) |
---|
1478 | return Inflate (tp); |
---|
1479 | |
---|
1480 | var ec = type as ElementTypeSpec; |
---|
1481 | if (ec != null) { |
---|
1482 | var et = Inflate (ec.Element); |
---|
1483 | if (et != ec.Element) { |
---|
1484 | var ac = ec as ArrayContainer; |
---|
1485 | if (ac != null) |
---|
1486 | return ArrayContainer.MakeType (context.Module, et, ac.Rank); |
---|
1487 | |
---|
1488 | if (ec is PointerContainer) |
---|
1489 | return PointerContainer.MakeType (context.Module, et); |
---|
1490 | |
---|
1491 | throw new NotImplementedException (); |
---|
1492 | } |
---|
1493 | |
---|
1494 | return ec; |
---|
1495 | } |
---|
1496 | |
---|
1497 | if (type.Kind == MemberKind.MissingType) |
---|
1498 | return type; |
---|
1499 | |
---|
1500 | // |
---|
1501 | // When inflating a nested type, inflate its parent first |
---|
1502 | // in case it's using same type parameters (was inflated within the type) |
---|
1503 | // |
---|
1504 | TypeSpec[] targs; |
---|
1505 | int i = 0; |
---|
1506 | if (type.IsNested) { |
---|
1507 | var parent = Inflate (type.DeclaringType); |
---|
1508 | |
---|
1509 | // |
---|
1510 | // Keep the inflated type arguments |
---|
1511 | // |
---|
1512 | targs = type.TypeArguments; |
---|
1513 | |
---|
1514 | // |
---|
1515 | // When inflating imported nested type used inside same declaring type, we get TypeSpec |
---|
1516 | // because the import cache helps us to catch it. However, that means we have to look at |
---|
1517 | // type definition to get type argument (they are in fact type parameter in this case) |
---|
1518 | // |
---|
1519 | if (targs.Length == 0 && type.Arity > 0) |
---|
1520 | targs = type.MemberDefinition.TypeParameters; |
---|
1521 | |
---|
1522 | // |
---|
1523 | // Parent was inflated, find the same type on inflated type |
---|
1524 | // to use same cache for nested types on same generic parent |
---|
1525 | // |
---|
1526 | type = MemberCache.FindNestedType (parent, type.Name, type.Arity); |
---|
1527 | |
---|
1528 | // |
---|
1529 | // Handle the tricky case where parent shares local type arguments |
---|
1530 | // which means inflating inflated type |
---|
1531 | // |
---|
1532 | // class Test<T> { |
---|
1533 | // public static Nested<T> Foo () { return null; } |
---|
1534 | // |
---|
1535 | // public class Nested<U> {} |
---|
1536 | // } |
---|
1537 | // |
---|
1538 | // return type of Test<string>.Foo() has to be Test<string>.Nested<string> |
---|
1539 | // |
---|
1540 | if (targs.Length > 0) { |
---|
1541 | var inflated_targs = new TypeSpec[targs.Length]; |
---|
1542 | for (; i < targs.Length; ++i) |
---|
1543 | inflated_targs[i] = Inflate (targs[i]); |
---|
1544 | |
---|
1545 | type = type.MakeGenericType (context, inflated_targs); |
---|
1546 | } |
---|
1547 | |
---|
1548 | return type; |
---|
1549 | } |
---|
1550 | |
---|
1551 | // Nothing to do for non-generic type |
---|
1552 | if (type.Arity == 0) |
---|
1553 | return type; |
---|
1554 | |
---|
1555 | targs = new TypeSpec[type.Arity]; |
---|
1556 | |
---|
1557 | // |
---|
1558 | // Inflating using outside type arguments, var v = new Foo<int> (), class Foo<T> {} |
---|
1559 | // |
---|
1560 | if (type is InflatedTypeSpec) { |
---|
1561 | for (; i < targs.Length; ++i) |
---|
1562 | targs[i] = Inflate (type.TypeArguments[i]); |
---|
1563 | |
---|
1564 | type = type.GetDefinition (); |
---|
1565 | } else { |
---|
1566 | // |
---|
1567 | // Inflating parent using inside type arguments, class Foo<T> { ITest<T> foo; } |
---|
1568 | // |
---|
1569 | var args = type.MemberDefinition.TypeParameters; |
---|
1570 | foreach (var ds_tp in args) |
---|
1571 | targs[i++] = Inflate (ds_tp); |
---|
1572 | } |
---|
1573 | |
---|
1574 | return type.MakeGenericType (context, targs); |
---|
1575 | } |
---|
1576 | |
---|
1577 | public TypeSpec Inflate (TypeParameterSpec tp) |
---|
1578 | { |
---|
1579 | for (int i = 0; i < tparams.Length; ++i) |
---|
1580 | if (tparams [i] == tp) |
---|
1581 | return targs[i]; |
---|
1582 | |
---|
1583 | // This can happen when inflating nested types |
---|
1584 | // without type arguments specified |
---|
1585 | return tp; |
---|
1586 | } |
---|
1587 | } |
---|
1588 | |
---|
1589 | // |
---|
1590 | // Before emitting any code we have to change all MVAR references to VAR |
---|
1591 | // when the method is of generic type and has hoisted variables |
---|
1592 | // |
---|
1593 | public class TypeParameterMutator |
---|
1594 | { |
---|
1595 | readonly TypeParameters mvar; |
---|
1596 | readonly TypeParameters var; |
---|
1597 | readonly TypeParameterSpec[] src; |
---|
1598 | Dictionary<TypeSpec, TypeSpec> mutated_typespec; |
---|
1599 | |
---|
1600 | public TypeParameterMutator (TypeParameters mvar, TypeParameters var) |
---|
1601 | { |
---|
1602 | if (mvar.Count != var.Count) |
---|
1603 | throw new ArgumentException (); |
---|
1604 | |
---|
1605 | this.mvar = mvar; |
---|
1606 | this.var = var; |
---|
1607 | } |
---|
1608 | |
---|
1609 | public TypeParameterMutator (TypeParameterSpec[] srcVar, TypeParameters destVar) |
---|
1610 | { |
---|
1611 | if (srcVar.Length != destVar.Count) |
---|
1612 | throw new ArgumentException (); |
---|
1613 | |
---|
1614 | this.src = srcVar; |
---|
1615 | this.var = destVar; |
---|
1616 | } |
---|
1617 | |
---|
1618 | #region Properties |
---|
1619 | |
---|
1620 | public TypeParameters MethodTypeParameters { |
---|
1621 | get { |
---|
1622 | return mvar; |
---|
1623 | } |
---|
1624 | } |
---|
1625 | |
---|
1626 | #endregion |
---|
1627 | |
---|
1628 | public static TypeSpec GetMemberDeclaringType (TypeSpec type) |
---|
1629 | { |
---|
1630 | if (type is InflatedTypeSpec) { |
---|
1631 | if (type.DeclaringType == null) |
---|
1632 | return type.GetDefinition (); |
---|
1633 | |
---|
1634 | var parent = GetMemberDeclaringType (type.DeclaringType); |
---|
1635 | type = MemberCache.GetMember<TypeSpec> (parent, type); |
---|
1636 | } |
---|
1637 | |
---|
1638 | return type; |
---|
1639 | } |
---|
1640 | |
---|
1641 | public TypeSpec Mutate (TypeSpec ts) |
---|
1642 | { |
---|
1643 | TypeSpec value; |
---|
1644 | if (mutated_typespec != null && mutated_typespec.TryGetValue (ts, out value)) |
---|
1645 | return value; |
---|
1646 | |
---|
1647 | value = ts.Mutate (this); |
---|
1648 | if (mutated_typespec == null) |
---|
1649 | mutated_typespec = new Dictionary<TypeSpec, TypeSpec> (); |
---|
1650 | |
---|
1651 | mutated_typespec.Add (ts, value); |
---|
1652 | return value; |
---|
1653 | } |
---|
1654 | |
---|
1655 | public TypeParameterSpec Mutate (TypeParameterSpec tp) |
---|
1656 | { |
---|
1657 | if (mvar != null) { |
---|
1658 | for (int i = 0; i < mvar.Count; ++i) { |
---|
1659 | if (mvar[i].Type == tp) |
---|
1660 | return var[i].Type; |
---|
1661 | } |
---|
1662 | } else { |
---|
1663 | for (int i = 0; i < src.Length; ++i) { |
---|
1664 | if (src[i] == tp) |
---|
1665 | return var[i].Type; |
---|
1666 | } |
---|
1667 | } |
---|
1668 | |
---|
1669 | return tp; |
---|
1670 | } |
---|
1671 | |
---|
1672 | public TypeSpec[] Mutate (TypeSpec[] targs) |
---|
1673 | { |
---|
1674 | TypeSpec[] mutated = new TypeSpec[targs.Length]; |
---|
1675 | bool changed = false; |
---|
1676 | for (int i = 0; i < targs.Length; ++i) { |
---|
1677 | mutated[i] = Mutate (targs[i]); |
---|
1678 | changed |= targs[i] != mutated[i]; |
---|
1679 | } |
---|
1680 | |
---|
1681 | return changed ? mutated : targs; |
---|
1682 | } |
---|
1683 | } |
---|
1684 | |
---|
1685 | /// <summary> |
---|
1686 | /// A TypeExpr which already resolved to a type parameter. |
---|
1687 | /// </summary> |
---|
1688 | public class TypeParameterExpr : TypeExpression |
---|
1689 | { |
---|
1690 | public TypeParameterExpr (TypeParameter type_parameter, Location loc) |
---|
1691 | : base (type_parameter.Type, loc) |
---|
1692 | { |
---|
1693 | this.eclass = ExprClass.TypeParameter; |
---|
1694 | } |
---|
1695 | } |
---|
1696 | |
---|
1697 | public class InflatedTypeSpec : TypeSpec |
---|
1698 | { |
---|
1699 | TypeSpec[] targs; |
---|
1700 | TypeParameterSpec[] constraints; |
---|
1701 | readonly TypeSpec open_type; |
---|
1702 | readonly IModuleContext context; |
---|
1703 | |
---|
1704 | public InflatedTypeSpec (IModuleContext context, TypeSpec openType, TypeSpec declaringType, TypeSpec[] targs) |
---|
1705 | : base (openType.Kind, declaringType, openType.MemberDefinition, null, openType.Modifiers) |
---|
1706 | { |
---|
1707 | if (targs == null) |
---|
1708 | throw new ArgumentNullException ("targs"); |
---|
1709 | |
---|
1710 | this.state &= ~SharedStateFlags; |
---|
1711 | this.state |= (openType.state & SharedStateFlags); |
---|
1712 | |
---|
1713 | this.context = context; |
---|
1714 | this.open_type = openType; |
---|
1715 | this.targs = targs; |
---|
1716 | |
---|
1717 | foreach (var arg in targs) { |
---|
1718 | if (arg.HasDynamicElement || arg.BuiltinType == BuiltinTypeSpec.Type.Dynamic) { |
---|
1719 | state |= StateFlags.HasDynamicElement; |
---|
1720 | break; |
---|
1721 | } |
---|
1722 | } |
---|
1723 | |
---|
1724 | if (open_type.Kind == MemberKind.MissingType) |
---|
1725 | MemberCache = MemberCache.Empty; |
---|
1726 | |
---|
1727 | if ((open_type.Modifiers & Modifiers.COMPILER_GENERATED) != 0) |
---|
1728 | state |= StateFlags.ConstraintsChecked; |
---|
1729 | } |
---|
1730 | |
---|
1731 | #region Properties |
---|
1732 | |
---|
1733 | public override TypeSpec BaseType { |
---|
1734 | get { |
---|
1735 | if (cache == null || (state & StateFlags.PendingBaseTypeInflate) != 0) |
---|
1736 | InitializeMemberCache (true); |
---|
1737 | |
---|
1738 | return base.BaseType; |
---|
1739 | } |
---|
1740 | } |
---|
1741 | |
---|
1742 | // |
---|
1743 | // Inflated type parameters with constraints array, mapping with type arguments is based on index |
---|
1744 | // |
---|
1745 | public TypeParameterSpec[] Constraints { |
---|
1746 | get { |
---|
1747 | if (constraints == null) { |
---|
1748 | constraints = TypeParameterSpec.InflateConstraints (MemberDefinition.TypeParameters, l => l.CreateLocalInflator (context), this); |
---|
1749 | } |
---|
1750 | |
---|
1751 | return constraints; |
---|
1752 | } |
---|
1753 | } |
---|
1754 | |
---|
1755 | // |
---|
1756 | // Used to cache expensive constraints validation on constructed types |
---|
1757 | // |
---|
1758 | public bool HasConstraintsChecked { |
---|
1759 | get { |
---|
1760 | return (state & StateFlags.ConstraintsChecked) != 0; |
---|
1761 | } |
---|
1762 | set { |
---|
1763 | state = value ? state | StateFlags.ConstraintsChecked : state & ~StateFlags.ConstraintsChecked; |
---|
1764 | } |
---|
1765 | } |
---|
1766 | |
---|
1767 | public override IList<TypeSpec> Interfaces { |
---|
1768 | get { |
---|
1769 | if (cache == null) |
---|
1770 | InitializeMemberCache (true); |
---|
1771 | |
---|
1772 | return base.Interfaces; |
---|
1773 | } |
---|
1774 | } |
---|
1775 | |
---|
1776 | public override bool IsExpressionTreeType { |
---|
1777 | get { |
---|
1778 | return (open_type.state & StateFlags.InflatedExpressionType) != 0; |
---|
1779 | } |
---|
1780 | } |
---|
1781 | |
---|
1782 | public override bool IsArrayGenericInterface { |
---|
1783 | get { |
---|
1784 | return (open_type.state & StateFlags.GenericIterateInterface) != 0; |
---|
1785 | } |
---|
1786 | } |
---|
1787 | |
---|
1788 | public override bool IsGenericTask { |
---|
1789 | get { |
---|
1790 | return (open_type.state & StateFlags.GenericTask) != 0; |
---|
1791 | } |
---|
1792 | } |
---|
1793 | |
---|
1794 | public override bool IsNullableType { |
---|
1795 | get { |
---|
1796 | return (open_type.state & StateFlags.InflatedNullableType) != 0; |
---|
1797 | } |
---|
1798 | } |
---|
1799 | |
---|
1800 | // |
---|
1801 | // Types used to inflate the generic type |
---|
1802 | // |
---|
1803 | public override TypeSpec[] TypeArguments { |
---|
1804 | get { |
---|
1805 | return targs; |
---|
1806 | } |
---|
1807 | } |
---|
1808 | |
---|
1809 | #endregion |
---|
1810 | |
---|
1811 | public override bool AddInterface (TypeSpec iface) |
---|
1812 | { |
---|
1813 | var inflator = CreateLocalInflator (context); |
---|
1814 | iface = inflator.Inflate (iface); |
---|
1815 | if (iface == null) |
---|
1816 | return false; |
---|
1817 | |
---|
1818 | return base.AddInterface (iface); |
---|
1819 | } |
---|
1820 | |
---|
1821 | public static bool ContainsTypeParameter (TypeSpec type) |
---|
1822 | { |
---|
1823 | if (type.Kind == MemberKind.TypeParameter) |
---|
1824 | return true; |
---|
1825 | |
---|
1826 | var element_container = type as ElementTypeSpec; |
---|
1827 | if (element_container != null) |
---|
1828 | return ContainsTypeParameter (element_container.Element); |
---|
1829 | |
---|
1830 | foreach (var t in type.TypeArguments) { |
---|
1831 | if (ContainsTypeParameter (t)) { |
---|
1832 | return true; |
---|
1833 | } |
---|
1834 | } |
---|
1835 | |
---|
1836 | return false; |
---|
1837 | } |
---|
1838 | |
---|
1839 | public TypeParameterInflator CreateLocalInflator (IModuleContext context) |
---|
1840 | { |
---|
1841 | TypeParameterSpec[] tparams_full; |
---|
1842 | TypeSpec[] targs_full = targs; |
---|
1843 | if (IsNested) { |
---|
1844 | // |
---|
1845 | // Special case is needed when we are inflating an open type (nested type definition) |
---|
1846 | // on inflated parent. Consider following case |
---|
1847 | // |
---|
1848 | // Foo<T>.Bar<U> => Foo<string>.Bar<U> |
---|
1849 | // |
---|
1850 | // Any later inflation of Foo<string>.Bar<U> has to also inflate T if used inside Bar<U> |
---|
1851 | // |
---|
1852 | List<TypeSpec> merged_targs = null; |
---|
1853 | List<TypeParameterSpec> merged_tparams = null; |
---|
1854 | |
---|
1855 | var type = DeclaringType; |
---|
1856 | |
---|
1857 | do { |
---|
1858 | if (type.TypeArguments.Length > 0) { |
---|
1859 | if (merged_targs == null) { |
---|
1860 | merged_targs = new List<TypeSpec> (); |
---|
1861 | merged_tparams = new List<TypeParameterSpec> (); |
---|
1862 | if (targs.Length > 0) { |
---|
1863 | merged_targs.AddRange (targs); |
---|
1864 | merged_tparams.AddRange (open_type.MemberDefinition.TypeParameters); |
---|
1865 | } |
---|
1866 | } |
---|
1867 | merged_tparams.AddRange (type.MemberDefinition.TypeParameters); |
---|
1868 | merged_targs.AddRange (type.TypeArguments); |
---|
1869 | } |
---|
1870 | type = type.DeclaringType; |
---|
1871 | } while (type != null); |
---|
1872 | |
---|
1873 | if (merged_targs != null) { |
---|
1874 | // Type arguments are not in the right order but it should not matter in this case |
---|
1875 | targs_full = merged_targs.ToArray (); |
---|
1876 | tparams_full = merged_tparams.ToArray (); |
---|
1877 | } else if (targs.Length == 0) { |
---|
1878 | tparams_full = TypeParameterSpec.EmptyTypes; |
---|
1879 | } else { |
---|
1880 | tparams_full = open_type.MemberDefinition.TypeParameters; |
---|
1881 | } |
---|
1882 | } else if (targs.Length == 0) { |
---|
1883 | tparams_full = TypeParameterSpec.EmptyTypes; |
---|
1884 | } else { |
---|
1885 | tparams_full = open_type.MemberDefinition.TypeParameters; |
---|
1886 | } |
---|
1887 | |
---|
1888 | return new TypeParameterInflator (context, this, tparams_full, targs_full); |
---|
1889 | } |
---|
1890 | |
---|
1891 | MetaType CreateMetaInfo () |
---|
1892 | { |
---|
1893 | // |
---|
1894 | // Converts nested type arguments into right order |
---|
1895 | // Foo<string, bool>.Bar<int> => string, bool, int |
---|
1896 | // |
---|
1897 | var all = new List<MetaType> (); |
---|
1898 | TypeSpec type = this; |
---|
1899 | TypeSpec definition = type; |
---|
1900 | do { |
---|
1901 | if (type.GetDefinition().IsGeneric) { |
---|
1902 | all.InsertRange (0, |
---|
1903 | type.TypeArguments != TypeSpec.EmptyTypes ? |
---|
1904 | type.TypeArguments.Select (l => l.GetMetaInfo ()) : |
---|
1905 | type.MemberDefinition.TypeParameters.Select (l => l.GetMetaInfo ())); |
---|
1906 | } |
---|
1907 | |
---|
1908 | definition = definition.GetDefinition (); |
---|
1909 | type = type.DeclaringType; |
---|
1910 | } while (type != null); |
---|
1911 | |
---|
1912 | return definition.GetMetaInfo ().MakeGenericType (all.ToArray ()); |
---|
1913 | } |
---|
1914 | |
---|
1915 | public override ObsoleteAttribute GetAttributeObsolete () |
---|
1916 | { |
---|
1917 | return open_type.GetAttributeObsolete (); |
---|
1918 | } |
---|
1919 | |
---|
1920 | protected override bool IsNotCLSCompliant (out bool attrValue) |
---|
1921 | { |
---|
1922 | if (base.IsNotCLSCompliant (out attrValue)) |
---|
1923 | return true; |
---|
1924 | |
---|
1925 | foreach (var ta in TypeArguments) { |
---|
1926 | if (ta.MemberDefinition.CLSAttributeValue == false) |
---|
1927 | return true; |
---|
1928 | } |
---|
1929 | |
---|
1930 | return false; |
---|
1931 | } |
---|
1932 | |
---|
1933 | public override TypeSpec GetDefinition () |
---|
1934 | { |
---|
1935 | return open_type; |
---|
1936 | } |
---|
1937 | |
---|
1938 | public override MetaType GetMetaInfo () |
---|
1939 | { |
---|
1940 | if (info == null) |
---|
1941 | info = CreateMetaInfo (); |
---|
1942 | |
---|
1943 | return info; |
---|
1944 | } |
---|
1945 | |
---|
1946 | public override string GetSignatureForError () |
---|
1947 | { |
---|
1948 | if (IsNullableType) |
---|
1949 | return targs[0].GetSignatureForError () + "?"; |
---|
1950 | |
---|
1951 | return base.GetSignatureForError (); |
---|
1952 | } |
---|
1953 | |
---|
1954 | protected override string GetTypeNameSignature () |
---|
1955 | { |
---|
1956 | if (targs.Length == 0 || MemberDefinition is AnonymousTypeClass) |
---|
1957 | return null; |
---|
1958 | |
---|
1959 | return "<" + TypeManager.CSharpName (targs) + ">"; |
---|
1960 | } |
---|
1961 | |
---|
1962 | public bool HasDynamicArgument () |
---|
1963 | { |
---|
1964 | for (int i = 0; i < targs.Length; ++i) { |
---|
1965 | var item = targs[i]; |
---|
1966 | |
---|
1967 | if (item.BuiltinType == BuiltinTypeSpec.Type.Dynamic) |
---|
1968 | return true; |
---|
1969 | |
---|
1970 | if (item is InflatedTypeSpec) { |
---|
1971 | if (((InflatedTypeSpec) item).HasDynamicArgument ()) |
---|
1972 | return true; |
---|
1973 | |
---|
1974 | continue; |
---|
1975 | } |
---|
1976 | |
---|
1977 | if (item.IsArray) { |
---|
1978 | while (item.IsArray) { |
---|
1979 | item = ((ArrayContainer) item).Element; |
---|
1980 | } |
---|
1981 | |
---|
1982 | if (item.BuiltinType == BuiltinTypeSpec.Type.Dynamic) |
---|
1983 | return true; |
---|
1984 | } |
---|
1985 | } |
---|
1986 | |
---|
1987 | return false; |
---|
1988 | } |
---|
1989 | |
---|
1990 | protected override void InitializeMemberCache (bool onlyTypes) |
---|
1991 | { |
---|
1992 | if (cache == null) { |
---|
1993 | var open_cache = onlyTypes ? open_type.MemberCacheTypes : open_type.MemberCache; |
---|
1994 | |
---|
1995 | // Surprisingly, calling MemberCache on open type could meantime create cache on this type |
---|
1996 | // for imported type parameter constraints referencing nested type of this declaration |
---|
1997 | if (cache == null) |
---|
1998 | cache = new MemberCache (open_cache); |
---|
1999 | } |
---|
2000 | |
---|
2001 | var inflator = CreateLocalInflator (context); |
---|
2002 | |
---|
2003 | // |
---|
2004 | // Two stage inflate due to possible nested types recursive |
---|
2005 | // references |
---|
2006 | // |
---|
2007 | // class A<T> { |
---|
2008 | // B b; |
---|
2009 | // class B { |
---|
2010 | // T Value; |
---|
2011 | // } |
---|
2012 | // } |
---|
2013 | // |
---|
2014 | // When resolving type of `b' members of `B' cannot be |
---|
2015 | // inflated because are not yet available in membercache |
---|
2016 | // |
---|
2017 | if ((state & StateFlags.PendingMemberCacheMembers) == 0) { |
---|
2018 | open_type.MemberCacheTypes.InflateTypes (cache, inflator); |
---|
2019 | |
---|
2020 | // |
---|
2021 | // Inflate any implemented interfaces |
---|
2022 | // |
---|
2023 | if (open_type.Interfaces != null) { |
---|
2024 | ifaces = new List<TypeSpec> (open_type.Interfaces.Count); |
---|
2025 | foreach (var iface in open_type.Interfaces) { |
---|
2026 | var iface_inflated = inflator.Inflate (iface); |
---|
2027 | if (iface_inflated == null) |
---|
2028 | continue; |
---|
2029 | |
---|
2030 | base.AddInterface (iface_inflated); |
---|
2031 | } |
---|
2032 | } |
---|
2033 | |
---|
2034 | // |
---|
2035 | // Handles the tricky case of recursive nested base generic type |
---|
2036 | // |
---|
2037 | // class A<T> : Base<A<T>.Nested> { |
---|
2038 | // class Nested {} |
---|
2039 | // } |
---|
2040 | // |
---|
2041 | // When inflating A<T>. base type is not yet known, secondary |
---|
2042 | // inflation is required (not common case) once base scope |
---|
2043 | // is known |
---|
2044 | // |
---|
2045 | if (open_type.BaseType == null) { |
---|
2046 | if (IsClass) |
---|
2047 | state |= StateFlags.PendingBaseTypeInflate; |
---|
2048 | } else { |
---|
2049 | BaseType = inflator.Inflate (open_type.BaseType); |
---|
2050 | } |
---|
2051 | } else if ((state & StateFlags.PendingBaseTypeInflate) != 0) { |
---|
2052 | // |
---|
2053 | // It can happen when resolving base type without being defined |
---|
2054 | // which is not allowed to happen and will always lead to an error |
---|
2055 | // |
---|
2056 | // class B { class N {} } |
---|
2057 | // class A<T> : A<B.N> {} |
---|
2058 | // |
---|
2059 | if (open_type.BaseType == null) |
---|
2060 | return; |
---|
2061 | |
---|
2062 | BaseType = inflator.Inflate (open_type.BaseType); |
---|
2063 | state &= ~StateFlags.PendingBaseTypeInflate; |
---|
2064 | } |
---|
2065 | |
---|
2066 | if (onlyTypes) { |
---|
2067 | state |= StateFlags.PendingMemberCacheMembers; |
---|
2068 | return; |
---|
2069 | } |
---|
2070 | |
---|
2071 | var tc = open_type.MemberDefinition as TypeDefinition; |
---|
2072 | if (tc != null && !tc.HasMembersDefined) { |
---|
2073 | // |
---|
2074 | // Inflating MemberCache with undefined members |
---|
2075 | // |
---|
2076 | return; |
---|
2077 | } |
---|
2078 | |
---|
2079 | if ((state & StateFlags.PendingBaseTypeInflate) != 0) { |
---|
2080 | BaseType = inflator.Inflate (open_type.BaseType); |
---|
2081 | state &= ~StateFlags.PendingBaseTypeInflate; |
---|
2082 | } |
---|
2083 | |
---|
2084 | state &= ~StateFlags.PendingMemberCacheMembers; |
---|
2085 | open_type.MemberCache.InflateMembers (cache, open_type, inflator); |
---|
2086 | } |
---|
2087 | |
---|
2088 | public override TypeSpec Mutate (TypeParameterMutator mutator) |
---|
2089 | { |
---|
2090 | var targs = TypeArguments; |
---|
2091 | if (targs != null) |
---|
2092 | targs = mutator.Mutate (targs); |
---|
2093 | |
---|
2094 | var decl = DeclaringType; |
---|
2095 | if (IsNested && DeclaringType.IsGenericOrParentIsGeneric) |
---|
2096 | decl = mutator.Mutate (decl); |
---|
2097 | |
---|
2098 | if (targs == TypeArguments && decl == DeclaringType) |
---|
2099 | return this; |
---|
2100 | |
---|
2101 | var mutated = (InflatedTypeSpec) MemberwiseClone (); |
---|
2102 | if (decl != DeclaringType) { |
---|
2103 | // Gets back MethodInfo in case of metaInfo was inflated |
---|
2104 | //mutated.info = MemberCache.GetMember<TypeSpec> (DeclaringType.GetDefinition (), this).info; |
---|
2105 | |
---|
2106 | mutated.declaringType = decl; |
---|
2107 | mutated.state |= StateFlags.PendingMetaInflate; |
---|
2108 | } |
---|
2109 | |
---|
2110 | if (targs != null) { |
---|
2111 | mutated.targs = targs; |
---|
2112 | mutated.info = null; |
---|
2113 | } |
---|
2114 | |
---|
2115 | return mutated; |
---|
2116 | } |
---|
2117 | } |
---|
2118 | |
---|
2119 | |
---|
2120 | // |
---|
2121 | // Tracks the type arguments when instantiating a generic type. It's used |
---|
2122 | // by both type arguments and type parameters |
---|
2123 | // |
---|
2124 | public class TypeArguments |
---|
2125 | { |
---|
2126 | List<FullNamedExpression> args; |
---|
2127 | TypeSpec[] atypes; |
---|
2128 | |
---|
2129 | public List<FullNamedExpression> Args { |
---|
2130 | get { return this.args; } |
---|
2131 | } |
---|
2132 | |
---|
2133 | public TypeArguments (params FullNamedExpression[] types) |
---|
2134 | { |
---|
2135 | this.args = new List<FullNamedExpression> (types); |
---|
2136 | } |
---|
2137 | |
---|
2138 | public void Add (FullNamedExpression type) |
---|
2139 | { |
---|
2140 | args.Add (type); |
---|
2141 | } |
---|
2142 | |
---|
2143 | /// <summary> |
---|
2144 | /// We may only be used after Resolve() is called and return the fully |
---|
2145 | /// resolved types. |
---|
2146 | /// </summary> |
---|
2147 | // TODO: Not needed, just return type from resolve |
---|
2148 | public TypeSpec[] Arguments { |
---|
2149 | get { |
---|
2150 | return atypes; |
---|
2151 | } |
---|
2152 | set { |
---|
2153 | atypes = value; |
---|
2154 | } |
---|
2155 | } |
---|
2156 | |
---|
2157 | public int Count { |
---|
2158 | get { |
---|
2159 | return args.Count; |
---|
2160 | } |
---|
2161 | } |
---|
2162 | |
---|
2163 | public virtual bool IsEmpty { |
---|
2164 | get { |
---|
2165 | return false; |
---|
2166 | } |
---|
2167 | } |
---|
2168 | |
---|
2169 | public List<FullNamedExpression> TypeExpressions { |
---|
2170 | get { |
---|
2171 | return this.args; |
---|
2172 | } |
---|
2173 | } |
---|
2174 | |
---|
2175 | public string GetSignatureForError() |
---|
2176 | { |
---|
2177 | StringBuilder sb = new StringBuilder (); |
---|
2178 | for (int i = 0; i < Count; ++i) { |
---|
2179 | var expr = args[i]; |
---|
2180 | if (expr != null) |
---|
2181 | sb.Append (expr.GetSignatureForError ()); |
---|
2182 | |
---|
2183 | if (i + 1 < Count) |
---|
2184 | sb.Append (','); |
---|
2185 | } |
---|
2186 | |
---|
2187 | return sb.ToString (); |
---|
2188 | } |
---|
2189 | |
---|
2190 | /// <summary> |
---|
2191 | /// Resolve the type arguments. |
---|
2192 | /// </summary> |
---|
2193 | public virtual bool Resolve (IMemberContext ec) |
---|
2194 | { |
---|
2195 | if (atypes != null) |
---|
2196 | return true; |
---|
2197 | |
---|
2198 | int count = args.Count; |
---|
2199 | bool ok = true; |
---|
2200 | |
---|
2201 | atypes = new TypeSpec [count]; |
---|
2202 | |
---|
2203 | var errors = ec.Module.Compiler.Report.Errors; |
---|
2204 | |
---|
2205 | for (int i = 0; i < count; i++){ |
---|
2206 | var te = args[i].ResolveAsType (ec); |
---|
2207 | if (te == null) { |
---|
2208 | ok = false; |
---|
2209 | continue; |
---|
2210 | } |
---|
2211 | |
---|
2212 | atypes[i] = te; |
---|
2213 | |
---|
2214 | if (te.IsStatic) { |
---|
2215 | ec.Module.Compiler.Report.Error (718, args[i].Location, "`{0}': static classes cannot be used as generic arguments", |
---|
2216 | te.GetSignatureForError ()); |
---|
2217 | ok = false; |
---|
2218 | } |
---|
2219 | |
---|
2220 | if (te.IsPointer || te.IsSpecialRuntimeType) { |
---|
2221 | ec.Module.Compiler.Report.Error (306, args[i].Location, |
---|
2222 | "The type `{0}' may not be used as a type argument", |
---|
2223 | te.GetSignatureForError ()); |
---|
2224 | ok = false; |
---|
2225 | } |
---|
2226 | } |
---|
2227 | |
---|
2228 | if (!ok || errors != ec.Module.Compiler.Report.Errors) |
---|
2229 | atypes = null; |
---|
2230 | |
---|
2231 | return ok; |
---|
2232 | } |
---|
2233 | |
---|
2234 | public TypeArguments Clone () |
---|
2235 | { |
---|
2236 | TypeArguments copy = new TypeArguments (); |
---|
2237 | foreach (var ta in args) |
---|
2238 | copy.args.Add (ta); |
---|
2239 | |
---|
2240 | return copy; |
---|
2241 | } |
---|
2242 | } |
---|
2243 | |
---|
2244 | public class UnboundTypeArguments : TypeArguments |
---|
2245 | { |
---|
2246 | public UnboundTypeArguments (int arity) |
---|
2247 | : base (new FullNamedExpression[arity]) |
---|
2248 | { |
---|
2249 | } |
---|
2250 | |
---|
2251 | public override bool IsEmpty { |
---|
2252 | get { |
---|
2253 | return true; |
---|
2254 | } |
---|
2255 | } |
---|
2256 | |
---|
2257 | public override bool Resolve (IMemberContext ec) |
---|
2258 | { |
---|
2259 | // Nothing to be resolved |
---|
2260 | return true; |
---|
2261 | } |
---|
2262 | } |
---|
2263 | |
---|
2264 | public class TypeParameters |
---|
2265 | { |
---|
2266 | List<TypeParameter> names; |
---|
2267 | TypeParameterSpec[] types; |
---|
2268 | |
---|
2269 | public TypeParameters () |
---|
2270 | { |
---|
2271 | names = new List<TypeParameter> (); |
---|
2272 | } |
---|
2273 | |
---|
2274 | public TypeParameters (int count) |
---|
2275 | { |
---|
2276 | names = new List<TypeParameter> (count); |
---|
2277 | } |
---|
2278 | |
---|
2279 | #region Properties |
---|
2280 | |
---|
2281 | public int Count { |
---|
2282 | get { |
---|
2283 | return names.Count; |
---|
2284 | } |
---|
2285 | } |
---|
2286 | |
---|
2287 | public TypeParameterSpec[] Types { |
---|
2288 | get { |
---|
2289 | return types; |
---|
2290 | } |
---|
2291 | } |
---|
2292 | |
---|
2293 | #endregion |
---|
2294 | |
---|
2295 | public void Add (TypeParameter tparam) |
---|
2296 | { |
---|
2297 | names.Add (tparam); |
---|
2298 | } |
---|
2299 | |
---|
2300 | public void Add (TypeParameters tparams) |
---|
2301 | { |
---|
2302 | names.AddRange (tparams.names); |
---|
2303 | } |
---|
2304 | |
---|
2305 | public void Create (TypeSpec declaringType, int parentOffset, TypeContainer parent) |
---|
2306 | { |
---|
2307 | types = new TypeParameterSpec[Count]; |
---|
2308 | for (int i = 0; i < types.Length; ++i) { |
---|
2309 | var tp = names[i]; |
---|
2310 | |
---|
2311 | tp.Create (declaringType, parent); |
---|
2312 | types[i] = tp.Type; |
---|
2313 | types[i].DeclaredPosition = i + parentOffset; |
---|
2314 | |
---|
2315 | if (tp.Variance != Variance.None && !(declaringType != null && (declaringType.Kind == MemberKind.Interface || declaringType.Kind == MemberKind.Delegate))) { |
---|
2316 | parent.Compiler.Report.Error (1960, tp.Location, "Variant type parameters can only be used with interfaces and delegates"); |
---|
2317 | } |
---|
2318 | } |
---|
2319 | } |
---|
2320 | |
---|
2321 | public void Define (GenericTypeParameterBuilder[] builders) |
---|
2322 | { |
---|
2323 | for (int i = 0; i < types.Length; ++i) { |
---|
2324 | var tp = names[i]; |
---|
2325 | tp.Define (builders [types [i].DeclaredPosition]); |
---|
2326 | } |
---|
2327 | } |
---|
2328 | |
---|
2329 | public TypeParameter this[int index] { |
---|
2330 | get { |
---|
2331 | return names [index]; |
---|
2332 | } |
---|
2333 | set { |
---|
2334 | names[index] = value; |
---|
2335 | } |
---|
2336 | } |
---|
2337 | |
---|
2338 | public TypeParameter Find (string name) |
---|
2339 | { |
---|
2340 | foreach (var tp in names) { |
---|
2341 | if (tp.Name == name) |
---|
2342 | return tp; |
---|
2343 | } |
---|
2344 | |
---|
2345 | return null; |
---|
2346 | } |
---|
2347 | |
---|
2348 | public string[] GetAllNames () |
---|
2349 | { |
---|
2350 | return names.Select (l => l.Name).ToArray (); |
---|
2351 | } |
---|
2352 | |
---|
2353 | public string GetSignatureForError () |
---|
2354 | { |
---|
2355 | StringBuilder sb = new StringBuilder (); |
---|
2356 | for (int i = 0; i < Count; ++i) { |
---|
2357 | if (i > 0) |
---|
2358 | sb.Append (','); |
---|
2359 | |
---|
2360 | var name = names[i]; |
---|
2361 | if (name != null) |
---|
2362 | sb.Append (name.GetSignatureForError ()); |
---|
2363 | } |
---|
2364 | |
---|
2365 | return sb.ToString (); |
---|
2366 | } |
---|
2367 | |
---|
2368 | |
---|
2369 | public void CheckPartialConstraints (Method part) |
---|
2370 | { |
---|
2371 | var partTypeParameters = part.CurrentTypeParameters; |
---|
2372 | |
---|
2373 | for (int i = 0; i < Count; i++) { |
---|
2374 | var tp_a = names[i]; |
---|
2375 | var tp_b = partTypeParameters [i]; |
---|
2376 | if (tp_a.Constraints == null) { |
---|
2377 | if (tp_b.Constraints == null) |
---|
2378 | continue; |
---|
2379 | } else if (tp_b.Constraints != null && tp_a.Type.HasSameConstraintsDefinition (tp_b.Type)) { |
---|
2380 | continue; |
---|
2381 | } |
---|
2382 | |
---|
2383 | part.Compiler.Report.SymbolRelatedToPreviousError (this[i].CurrentMemberDefinition.Location, ""); |
---|
2384 | part.Compiler.Report.Error (761, part.Location, |
---|
2385 | "Partial method declarations of `{0}' have inconsistent constraints for type parameter `{1}'", |
---|
2386 | part.GetSignatureForError (), partTypeParameters[i].GetSignatureForError ()); |
---|
2387 | } |
---|
2388 | } |
---|
2389 | |
---|
2390 | public void UpdateConstraints (TypeDefinition part) |
---|
2391 | { |
---|
2392 | var partTypeParameters = part.MemberName.TypeParameters; |
---|
2393 | |
---|
2394 | for (int i = 0; i < Count; i++) { |
---|
2395 | var tp = names [i]; |
---|
2396 | if (tp.AddPartialConstraints (part, partTypeParameters [i])) |
---|
2397 | continue; |
---|
2398 | |
---|
2399 | part.Compiler.Report.SymbolRelatedToPreviousError (this[i].CurrentMemberDefinition); |
---|
2400 | part.Compiler.Report.Error (265, part.Location, |
---|
2401 | "Partial declarations of `{0}' have inconsistent constraints for type parameter `{1}'", |
---|
2402 | part.GetSignatureForError (), tp.GetSignatureForError ()); |
---|
2403 | } |
---|
2404 | } |
---|
2405 | |
---|
2406 | public void VerifyClsCompliance () |
---|
2407 | { |
---|
2408 | foreach (var tp in names) { |
---|
2409 | tp.VerifyClsCompliance (); |
---|
2410 | } |
---|
2411 | } |
---|
2412 | } |
---|
2413 | |
---|
2414 | // |
---|
2415 | // A type expression of generic type with type arguments |
---|
2416 | // |
---|
2417 | class GenericTypeExpr : TypeExpr |
---|
2418 | { |
---|
2419 | TypeArguments args; |
---|
2420 | TypeSpec open_type; |
---|
2421 | |
---|
2422 | /// <summary> |
---|
2423 | /// Instantiate the generic type `t' with the type arguments `args'. |
---|
2424 | /// Use this constructor if you already know the fully resolved |
---|
2425 | /// generic type. |
---|
2426 | /// </summary> |
---|
2427 | public GenericTypeExpr (TypeSpec open_type, TypeArguments args, Location l) |
---|
2428 | { |
---|
2429 | this.open_type = open_type; |
---|
2430 | loc = l; |
---|
2431 | this.args = args; |
---|
2432 | } |
---|
2433 | |
---|
2434 | public override string GetSignatureForError () |
---|
2435 | { |
---|
2436 | return type.GetSignatureForError (); |
---|
2437 | } |
---|
2438 | |
---|
2439 | public override TypeSpec ResolveAsType (IMemberContext mc, bool allowUnboundTypeArguments = false) |
---|
2440 | { |
---|
2441 | if (eclass != ExprClass.Unresolved) |
---|
2442 | return type; |
---|
2443 | |
---|
2444 | if (!args.Resolve (mc)) |
---|
2445 | return null; |
---|
2446 | |
---|
2447 | TypeSpec[] atypes = args.Arguments; |
---|
2448 | if (atypes == null) |
---|
2449 | return null; |
---|
2450 | |
---|
2451 | // |
---|
2452 | // Now bind the parameters |
---|
2453 | // |
---|
2454 | var inflated = open_type.MakeGenericType (mc, atypes); |
---|
2455 | type = inflated; |
---|
2456 | eclass = ExprClass.Type; |
---|
2457 | |
---|
2458 | // |
---|
2459 | // The constraints can be checked only when full type hierarchy is known |
---|
2460 | // |
---|
2461 | if (!inflated.HasConstraintsChecked && mc.Module.HasTypesFullyDefined) { |
---|
2462 | var constraints = inflated.Constraints; |
---|
2463 | if (constraints != null) { |
---|
2464 | var cc = new ConstraintChecker (mc); |
---|
2465 | if (cc.CheckAll (open_type, atypes, constraints, loc)) { |
---|
2466 | inflated.HasConstraintsChecked = true; |
---|
2467 | } |
---|
2468 | } |
---|
2469 | } |
---|
2470 | |
---|
2471 | return type; |
---|
2472 | } |
---|
2473 | |
---|
2474 | public override bool Equals (object obj) |
---|
2475 | { |
---|
2476 | GenericTypeExpr cobj = obj as GenericTypeExpr; |
---|
2477 | if (cobj == null) |
---|
2478 | return false; |
---|
2479 | |
---|
2480 | if ((type == null) || (cobj.type == null)) |
---|
2481 | return false; |
---|
2482 | |
---|
2483 | return type == cobj.type; |
---|
2484 | } |
---|
2485 | |
---|
2486 | public override int GetHashCode () |
---|
2487 | { |
---|
2488 | return base.GetHashCode (); |
---|
2489 | } |
---|
2490 | } |
---|
2491 | |
---|
2492 | // |
---|
2493 | // Generic type with unbound type arguments, used for typeof (G<,,>) |
---|
2494 | // |
---|
2495 | class GenericOpenTypeExpr : TypeExpression |
---|
2496 | { |
---|
2497 | public GenericOpenTypeExpr (TypeSpec type, /*UnboundTypeArguments args,*/ Location loc) |
---|
2498 | : base (type.GetDefinition (), loc) |
---|
2499 | { |
---|
2500 | } |
---|
2501 | } |
---|
2502 | |
---|
2503 | struct ConstraintChecker |
---|
2504 | { |
---|
2505 | IMemberContext mc; |
---|
2506 | bool recursive_checks; |
---|
2507 | |
---|
2508 | public ConstraintChecker (IMemberContext ctx) |
---|
2509 | { |
---|
2510 | this.mc = ctx; |
---|
2511 | recursive_checks = false; |
---|
2512 | } |
---|
2513 | |
---|
2514 | // |
---|
2515 | // Checks the constraints of open generic type against type |
---|
2516 | // arguments. This version is used for types which could not be |
---|
2517 | // checked immediatelly during construction because the type |
---|
2518 | // hierarchy was not yet fully setup (before Emit phase) |
---|
2519 | // |
---|
2520 | public static bool Check (IMemberContext mc, TypeSpec type, Location loc) |
---|
2521 | { |
---|
2522 | // |
---|
2523 | // Check declaring type first if there is any |
---|
2524 | // |
---|
2525 | if (type.DeclaringType != null && !Check (mc, type.DeclaringType, loc)) |
---|
2526 | return false; |
---|
2527 | |
---|
2528 | while (type is ElementTypeSpec) |
---|
2529 | type = ((ElementTypeSpec) type).Element; |
---|
2530 | |
---|
2531 | if (type.Arity == 0) |
---|
2532 | return true; |
---|
2533 | |
---|
2534 | var gtype = type as InflatedTypeSpec; |
---|
2535 | if (gtype == null) |
---|
2536 | return true; |
---|
2537 | |
---|
2538 | var constraints = gtype.Constraints; |
---|
2539 | if (constraints == null) |
---|
2540 | return true; |
---|
2541 | |
---|
2542 | if (gtype.HasConstraintsChecked) |
---|
2543 | return true; |
---|
2544 | |
---|
2545 | var cc = new ConstraintChecker (mc); |
---|
2546 | cc.recursive_checks = true; |
---|
2547 | |
---|
2548 | if (cc.CheckAll (gtype.GetDefinition (), type.TypeArguments, constraints, loc)) { |
---|
2549 | gtype.HasConstraintsChecked = true; |
---|
2550 | return true; |
---|
2551 | } |
---|
2552 | |
---|
2553 | return false; |
---|
2554 | } |
---|
2555 | |
---|
2556 | // |
---|
2557 | // Checks all type arguments againts type parameters constraints |
---|
2558 | // NOTE: It can run in probing mode when `this.mc' is null |
---|
2559 | // |
---|
2560 | public bool CheckAll (MemberSpec context, TypeSpec[] targs, TypeParameterSpec[] tparams, Location loc) |
---|
2561 | { |
---|
2562 | for (int i = 0; i < tparams.Length; i++) { |
---|
2563 | var targ = targs[i]; |
---|
2564 | if (!CheckConstraint (context, targ, tparams [i], loc)) |
---|
2565 | return false; |
---|
2566 | |
---|
2567 | if (!recursive_checks) |
---|
2568 | continue; |
---|
2569 | |
---|
2570 | if (!Check (mc, targ, loc)) |
---|
2571 | return false; |
---|
2572 | } |
---|
2573 | |
---|
2574 | return true; |
---|
2575 | } |
---|
2576 | |
---|
2577 | bool CheckConstraint (MemberSpec context, TypeSpec atype, TypeParameterSpec tparam, Location loc) |
---|
2578 | { |
---|
2579 | // |
---|
2580 | // First, check the `class' and `struct' constraints. |
---|
2581 | // |
---|
2582 | if (tparam.HasSpecialClass && !TypeSpec.IsReferenceType (atype)) { |
---|
2583 | if (mc != null) { |
---|
2584 | mc.Module.Compiler.Report.Error (452, loc, |
---|
2585 | "The type `{0}' must be a reference type in order to use it as type parameter `{1}' in the generic type or method `{2}'", |
---|
2586 | atype.GetSignatureForError (), tparam.GetSignatureForError (), context.GetSignatureForError ()); |
---|
2587 | } |
---|
2588 | |
---|
2589 | return false; |
---|
2590 | } |
---|
2591 | |
---|
2592 | if (tparam.HasSpecialStruct && (!TypeSpec.IsValueType (atype) || atype.IsNullableType)) { |
---|
2593 | if (mc != null) { |
---|
2594 | mc.Module.Compiler.Report.Error (453, loc, |
---|
2595 | "The type `{0}' must be a non-nullable value type in order to use it as type parameter `{1}' in the generic type or method `{2}'", |
---|
2596 | atype.GetSignatureForError (), tparam.GetSignatureForError (), context.GetSignatureForError ()); |
---|
2597 | } |
---|
2598 | |
---|
2599 | return false; |
---|
2600 | } |
---|
2601 | |
---|
2602 | bool ok = true; |
---|
2603 | |
---|
2604 | // |
---|
2605 | // Check the class constraint |
---|
2606 | // |
---|
2607 | if (tparam.HasTypeConstraint) { |
---|
2608 | if (!CheckConversion (mc, context, atype, tparam, tparam.BaseType, loc)) { |
---|
2609 | if (mc == null) |
---|
2610 | return false; |
---|
2611 | |
---|
2612 | ok = false; |
---|
2613 | } |
---|
2614 | } |
---|
2615 | |
---|
2616 | // |
---|
2617 | // Check the interfaces constraints |
---|
2618 | // |
---|
2619 | if (tparam.InterfacesDefined != null) { |
---|
2620 | foreach (TypeSpec iface in tparam.InterfacesDefined) { |
---|
2621 | if (!CheckConversion (mc, context, atype, tparam, iface, loc)) { |
---|
2622 | if (mc == null) |
---|
2623 | return false; |
---|
2624 | |
---|
2625 | ok = false; |
---|
2626 | break; |
---|
2627 | } |
---|
2628 | } |
---|
2629 | } |
---|
2630 | |
---|
2631 | // |
---|
2632 | // Check the type parameter constraint |
---|
2633 | // |
---|
2634 | if (tparam.TypeArguments != null) { |
---|
2635 | foreach (var ta in tparam.TypeArguments) { |
---|
2636 | if (!CheckConversion (mc, context, atype, tparam, ta, loc)) { |
---|
2637 | if (mc == null) |
---|
2638 | return false; |
---|
2639 | |
---|
2640 | ok = false; |
---|
2641 | break; |
---|
2642 | } |
---|
2643 | } |
---|
2644 | } |
---|
2645 | |
---|
2646 | // |
---|
2647 | // Finally, check the constructor constraint. |
---|
2648 | // |
---|
2649 | if (!tparam.HasSpecialConstructor) |
---|
2650 | return ok; |
---|
2651 | |
---|
2652 | if (!HasDefaultConstructor (atype)) { |
---|
2653 | if (mc != null) { |
---|
2654 | mc.Module.Compiler.Report.SymbolRelatedToPreviousError (atype); |
---|
2655 | mc.Module.Compiler.Report.Error (310, loc, |
---|
2656 | "The type `{0}' must have a public parameterless constructor in order to use it as parameter `{1}' in the generic type or method `{2}'", |
---|
2657 | atype.GetSignatureForError (), tparam.GetSignatureForError (), context.GetSignatureForError ()); |
---|
2658 | } |
---|
2659 | return false; |
---|
2660 | } |
---|
2661 | |
---|
2662 | return ok; |
---|
2663 | } |
---|
2664 | |
---|
2665 | static bool HasDynamicTypeArgument (TypeSpec[] targs) |
---|
2666 | { |
---|
2667 | for (int i = 0; i < targs.Length; ++i) { |
---|
2668 | var targ = targs [i]; |
---|
2669 | if (targ.BuiltinType == BuiltinTypeSpec.Type.Dynamic) |
---|
2670 | return true; |
---|
2671 | |
---|
2672 | if (HasDynamicTypeArgument (targ.TypeArguments)) |
---|
2673 | return true; |
---|
2674 | } |
---|
2675 | |
---|
2676 | return false; |
---|
2677 | } |
---|
2678 | |
---|
2679 | bool CheckConversion (IMemberContext mc, MemberSpec context, TypeSpec atype, TypeParameterSpec tparam, TypeSpec ttype, Location loc) |
---|
2680 | { |
---|
2681 | if (atype == ttype) |
---|
2682 | return true; |
---|
2683 | |
---|
2684 | if (atype.IsGenericParameter) { |
---|
2685 | var tps = (TypeParameterSpec) atype; |
---|
2686 | if (tps.HasDependencyOn (ttype)) |
---|
2687 | return true; |
---|
2688 | |
---|
2689 | if (Convert.ImplicitTypeParameterConversion (null, tps, ttype) != null) |
---|
2690 | return true; |
---|
2691 | |
---|
2692 | } else if (TypeSpec.IsValueType (atype)) { |
---|
2693 | if (atype.IsNullableType) { |
---|
2694 | // |
---|
2695 | // LAMESPEC: Only identity or base type ValueType or Object satisfy nullable type |
---|
2696 | // |
---|
2697 | if (TypeSpec.IsBaseClass (atype, ttype, false)) |
---|
2698 | return true; |
---|
2699 | } else { |
---|
2700 | if (Convert.ImplicitBoxingConversion (null, atype, ttype) != null) |
---|
2701 | return true; |
---|
2702 | } |
---|
2703 | } else { |
---|
2704 | if (Convert.ImplicitReferenceConversionExists (atype, ttype) || Convert.ImplicitBoxingConversion (null, atype, ttype) != null) |
---|
2705 | return true; |
---|
2706 | } |
---|
2707 | |
---|
2708 | if (mc != null) { |
---|
2709 | mc.Module.Compiler.Report.SymbolRelatedToPreviousError (tparam); |
---|
2710 | if (atype.IsGenericParameter) { |
---|
2711 | mc.Module.Compiler.Report.Error (314, loc, |
---|
2712 | "The type `{0}' cannot be used as type parameter `{1}' in the generic type or method `{2}'. There is no boxing or type parameter conversion from `{0}' to `{3}'", |
---|
2713 | atype.GetSignatureForError (), tparam.GetSignatureForError (), context.GetSignatureForError (), ttype.GetSignatureForError ()); |
---|
2714 | } else if (TypeSpec.IsValueType (atype)) { |
---|
2715 | if (atype.IsNullableType) { |
---|
2716 | if (ttype.IsInterface) { |
---|
2717 | mc.Module.Compiler.Report.Error (313, loc, |
---|
2718 | "The type `{0}' cannot be used as type parameter `{1}' in the generic type or method `{2}'. The nullable type `{0}' never satisfies interface constraint `{3}'", |
---|
2719 | atype.GetSignatureForError (), tparam.GetSignatureForError (), context.GetSignatureForError (), ttype.GetSignatureForError ()); |
---|
2720 | } else { |
---|
2721 | mc.Module.Compiler.Report.Error (312, loc, |
---|
2722 | "The type `{0}' cannot be used as type parameter `{1}' in the generic type or method `{2}'. The nullable type `{0}' does not satisfy constraint `{3}'", |
---|
2723 | atype.GetSignatureForError (), tparam.GetSignatureForError (), context.GetSignatureForError (), ttype.GetSignatureForError ()); |
---|
2724 | } |
---|
2725 | } else { |
---|
2726 | mc.Module.Compiler.Report.Error (315, loc, |
---|
2727 | "The type `{0}' cannot be used as type parameter `{1}' in the generic type or method `{2}'. There is no boxing conversion from `{0}' to `{3}'", |
---|
2728 | atype.GetSignatureForError (), tparam.GetSignatureForError (), context.GetSignatureForError (), ttype.GetSignatureForError ()); |
---|
2729 | } |
---|
2730 | } else { |
---|
2731 | mc.Module.Compiler.Report.Error (311, loc, |
---|
2732 | "The type `{0}' cannot be used as type parameter `{1}' in the generic type or method `{2}'. There is no implicit reference conversion from `{0}' to `{3}'", |
---|
2733 | atype.GetSignatureForError (), tparam.GetSignatureForError (), context.GetSignatureForError (), ttype.GetSignatureForError ()); |
---|
2734 | } |
---|
2735 | } |
---|
2736 | |
---|
2737 | return false; |
---|
2738 | } |
---|
2739 | |
---|
2740 | static bool HasDefaultConstructor (TypeSpec atype) |
---|
2741 | { |
---|
2742 | var tp = atype as TypeParameterSpec; |
---|
2743 | if (tp != null) { |
---|
2744 | return tp.HasSpecialConstructor || tp.HasSpecialStruct; |
---|
2745 | } |
---|
2746 | |
---|
2747 | if (atype.IsStruct || atype.IsEnum) |
---|
2748 | return true; |
---|
2749 | |
---|
2750 | if (atype.IsAbstract) |
---|
2751 | return false; |
---|
2752 | |
---|
2753 | var tdef = atype.GetDefinition (); |
---|
2754 | |
---|
2755 | var found = MemberCache.FindMember (tdef, |
---|
2756 | MemberFilter.Constructor (ParametersCompiled.EmptyReadOnlyParameters), |
---|
2757 | BindingRestriction.DeclaredOnly | BindingRestriction.InstanceOnly); |
---|
2758 | |
---|
2759 | return found != null && (found.Modifiers & Modifiers.PUBLIC) != 0; |
---|
2760 | } |
---|
2761 | } |
---|
2762 | |
---|
2763 | // |
---|
2764 | // Implements C# type inference |
---|
2765 | // |
---|
2766 | class TypeInference |
---|
2767 | { |
---|
2768 | // |
---|
2769 | // Tracks successful rate of type inference |
---|
2770 | // |
---|
2771 | int score = int.MaxValue; |
---|
2772 | readonly Arguments arguments; |
---|
2773 | readonly int arg_count; |
---|
2774 | |
---|
2775 | public TypeInference (Arguments arguments) |
---|
2776 | { |
---|
2777 | this.arguments = arguments; |
---|
2778 | if (arguments != null) |
---|
2779 | arg_count = arguments.Count; |
---|
2780 | } |
---|
2781 | |
---|
2782 | public int InferenceScore { |
---|
2783 | get { |
---|
2784 | return score; |
---|
2785 | } |
---|
2786 | } |
---|
2787 | |
---|
2788 | public TypeSpec[] InferMethodArguments (ResolveContext ec, MethodSpec method) |
---|
2789 | { |
---|
2790 | var method_generic_args = method.GenericDefinition.TypeParameters; |
---|
2791 | TypeInferenceContext context = new TypeInferenceContext (method_generic_args); |
---|
2792 | if (!context.UnfixedVariableExists) |
---|
2793 | return TypeSpec.EmptyTypes; |
---|
2794 | |
---|
2795 | AParametersCollection pd = method.Parameters; |
---|
2796 | if (!InferInPhases (ec, context, pd)) |
---|
2797 | return null; |
---|
2798 | |
---|
2799 | return context.InferredTypeArguments; |
---|
2800 | } |
---|
2801 | |
---|
2802 | // |
---|
2803 | // Implements method type arguments inference |
---|
2804 | // |
---|
2805 | bool InferInPhases (ResolveContext ec, TypeInferenceContext tic, AParametersCollection methodParameters) |
---|
2806 | { |
---|
2807 | int params_arguments_start; |
---|
2808 | if (methodParameters.HasParams) { |
---|
2809 | params_arguments_start = methodParameters.Count - 1; |
---|
2810 | } else { |
---|
2811 | params_arguments_start = arg_count; |
---|
2812 | } |
---|
2813 | |
---|
2814 | TypeSpec [] ptypes = methodParameters.Types; |
---|
2815 | |
---|
2816 | // |
---|
2817 | // The first inference phase |
---|
2818 | // |
---|
2819 | TypeSpec method_parameter = null; |
---|
2820 | for (int i = 0; i < arg_count; i++) { |
---|
2821 | Argument a = arguments [i]; |
---|
2822 | if (a == null) |
---|
2823 | continue; |
---|
2824 | |
---|
2825 | if (i < params_arguments_start) { |
---|
2826 | method_parameter = methodParameters.Types [i]; |
---|
2827 | } else if (i == params_arguments_start) { |
---|
2828 | if (arg_count == params_arguments_start + 1 && TypeManager.HasElementType (a.Type)) |
---|
2829 | method_parameter = methodParameters.Types [params_arguments_start]; |
---|
2830 | else |
---|
2831 | method_parameter = TypeManager.GetElementType (methodParameters.Types [params_arguments_start]); |
---|
2832 | |
---|
2833 | ptypes = (TypeSpec[]) ptypes.Clone (); |
---|
2834 | ptypes [i] = method_parameter; |
---|
2835 | } |
---|
2836 | |
---|
2837 | // |
---|
2838 | // When a lambda expression, an anonymous method |
---|
2839 | // is used an explicit argument type inference takes a place |
---|
2840 | // |
---|
2841 | AnonymousMethodExpression am = a.Expr as AnonymousMethodExpression; |
---|
2842 | if (am != null) { |
---|
2843 | if (am.ExplicitTypeInference (tic, method_parameter)) |
---|
2844 | --score; |
---|
2845 | continue; |
---|
2846 | } |
---|
2847 | |
---|
2848 | if (a.IsByRef) { |
---|
2849 | score -= tic.ExactInference (a.Type, method_parameter); |
---|
2850 | continue; |
---|
2851 | } |
---|
2852 | |
---|
2853 | if (a.Expr.Type == InternalType.NullLiteral) |
---|
2854 | continue; |
---|
2855 | |
---|
2856 | if (TypeSpec.IsValueType (method_parameter)) { |
---|
2857 | score -= tic.LowerBoundInference (a.Type, method_parameter); |
---|
2858 | continue; |
---|
2859 | } |
---|
2860 | |
---|
2861 | // |
---|
2862 | // Otherwise an output type inference is made |
---|
2863 | // |
---|
2864 | score -= tic.OutputTypeInference (ec, a.Expr, method_parameter); |
---|
2865 | } |
---|
2866 | |
---|
2867 | // |
---|
2868 | // Part of the second phase but because it happens only once |
---|
2869 | // we don't need to call it in cycle |
---|
2870 | // |
---|
2871 | bool fixed_any = false; |
---|
2872 | if (!tic.FixIndependentTypeArguments (ec, ptypes, ref fixed_any)) |
---|
2873 | return false; |
---|
2874 | |
---|
2875 | return DoSecondPhase (ec, tic, ptypes, !fixed_any); |
---|
2876 | } |
---|
2877 | |
---|
2878 | bool DoSecondPhase (ResolveContext ec, TypeInferenceContext tic, TypeSpec[] methodParameters, bool fixDependent) |
---|
2879 | { |
---|
2880 | bool fixed_any = false; |
---|
2881 | if (fixDependent && !tic.FixDependentTypes (ec, ref fixed_any)) |
---|
2882 | return false; |
---|
2883 | |
---|
2884 | // If no further unfixed type variables exist, type inference succeeds |
---|
2885 | if (!tic.UnfixedVariableExists) |
---|
2886 | return true; |
---|
2887 | |
---|
2888 | if (!fixed_any && fixDependent) |
---|
2889 | return false; |
---|
2890 | |
---|
2891 | // For all arguments where the corresponding argument output types |
---|
2892 | // contain unfixed type variables but the input types do not, |
---|
2893 | // an output type inference is made |
---|
2894 | for (int i = 0; i < arg_count; i++) { |
---|
2895 | |
---|
2896 | // Align params arguments |
---|
2897 | TypeSpec t_i = methodParameters [i >= methodParameters.Length ? methodParameters.Length - 1: i]; |
---|
2898 | |
---|
2899 | if (!t_i.IsDelegate) { |
---|
2900 | if (!t_i.IsExpressionTreeType) |
---|
2901 | continue; |
---|
2902 | |
---|
2903 | t_i = TypeManager.GetTypeArguments (t_i) [0]; |
---|
2904 | } |
---|
2905 | |
---|
2906 | var mi = Delegate.GetInvokeMethod (t_i); |
---|
2907 | TypeSpec rtype = mi.ReturnType; |
---|
2908 | |
---|
2909 | if (tic.IsReturnTypeNonDependent (mi, rtype)) { |
---|
2910 | // It can be null for default arguments |
---|
2911 | if (arguments[i] == null) |
---|
2912 | continue; |
---|
2913 | |
---|
2914 | score -= tic.OutputTypeInference (ec, arguments[i].Expr, t_i); |
---|
2915 | } |
---|
2916 | } |
---|
2917 | |
---|
2918 | |
---|
2919 | return DoSecondPhase (ec, tic, methodParameters, true); |
---|
2920 | } |
---|
2921 | } |
---|
2922 | |
---|
2923 | public class TypeInferenceContext |
---|
2924 | { |
---|
2925 | protected enum BoundKind |
---|
2926 | { |
---|
2927 | Exact = 0, |
---|
2928 | Lower = 1, |
---|
2929 | Upper = 2 |
---|
2930 | } |
---|
2931 | |
---|
2932 | struct BoundInfo : IEquatable<BoundInfo> |
---|
2933 | { |
---|
2934 | public readonly TypeSpec Type; |
---|
2935 | public readonly BoundKind Kind; |
---|
2936 | |
---|
2937 | public BoundInfo (TypeSpec type, BoundKind kind) |
---|
2938 | { |
---|
2939 | this.Type = type; |
---|
2940 | this.Kind = kind; |
---|
2941 | } |
---|
2942 | |
---|
2943 | public override int GetHashCode () |
---|
2944 | { |
---|
2945 | return Type.GetHashCode (); |
---|
2946 | } |
---|
2947 | |
---|
2948 | public Expression GetTypeExpression () |
---|
2949 | { |
---|
2950 | return new TypeExpression (Type, Location.Null); |
---|
2951 | } |
---|
2952 | |
---|
2953 | #region IEquatable<BoundInfo> Members |
---|
2954 | |
---|
2955 | public bool Equals (BoundInfo other) |
---|
2956 | { |
---|
2957 | return Type == other.Type && Kind == other.Kind; |
---|
2958 | } |
---|
2959 | |
---|
2960 | #endregion |
---|
2961 | } |
---|
2962 | |
---|
2963 | readonly TypeSpec[] tp_args; |
---|
2964 | readonly TypeSpec[] fixed_types; |
---|
2965 | readonly List<BoundInfo>[] bounds; |
---|
2966 | |
---|
2967 | // TODO MemberCache: Could it be TypeParameterSpec[] ?? |
---|
2968 | public TypeInferenceContext (TypeSpec[] typeArguments) |
---|
2969 | { |
---|
2970 | if (typeArguments.Length == 0) |
---|
2971 | throw new ArgumentException ("Empty generic arguments"); |
---|
2972 | |
---|
2973 | fixed_types = new TypeSpec [typeArguments.Length]; |
---|
2974 | for (int i = 0; i < typeArguments.Length; ++i) { |
---|
2975 | if (typeArguments [i].IsGenericParameter) { |
---|
2976 | if (bounds == null) { |
---|
2977 | bounds = new List<BoundInfo> [typeArguments.Length]; |
---|
2978 | tp_args = new TypeSpec [typeArguments.Length]; |
---|
2979 | } |
---|
2980 | tp_args [i] = typeArguments [i]; |
---|
2981 | } else { |
---|
2982 | fixed_types [i] = typeArguments [i]; |
---|
2983 | } |
---|
2984 | } |
---|
2985 | } |
---|
2986 | |
---|
2987 | // |
---|
2988 | // Used together with AddCommonTypeBound fo implement |
---|
2989 | // 7.4.2.13 Finding the best common type of a set of expressions |
---|
2990 | // |
---|
2991 | public TypeInferenceContext () |
---|
2992 | { |
---|
2993 | fixed_types = new TypeSpec [1]; |
---|
2994 | tp_args = new TypeSpec [1]; |
---|
2995 | tp_args[0] = InternalType.Arglist; // it can be any internal type |
---|
2996 | bounds = new List<BoundInfo> [1]; |
---|
2997 | } |
---|
2998 | |
---|
2999 | public TypeSpec[] InferredTypeArguments { |
---|
3000 | get { |
---|
3001 | return fixed_types; |
---|
3002 | } |
---|
3003 | } |
---|
3004 | |
---|
3005 | public void AddCommonTypeBound (TypeSpec type) |
---|
3006 | { |
---|
3007 | AddToBounds (new BoundInfo (type, BoundKind.Lower), 0, false); |
---|
3008 | } |
---|
3009 | |
---|
3010 | public void AddCommonTypeBoundAsync (TypeSpec type) |
---|
3011 | { |
---|
3012 | AddToBounds (new BoundInfo (type, BoundKind.Lower), 0, true); |
---|
3013 | } |
---|
3014 | |
---|
3015 | void AddToBounds (BoundInfo bound, int index, bool voidAllowed) |
---|
3016 | { |
---|
3017 | // |
---|
3018 | // Some types cannot be used as type arguments |
---|
3019 | // |
---|
3020 | if ((bound.Type.Kind == MemberKind.Void && !voidAllowed) || bound.Type.IsPointer || bound.Type.IsSpecialRuntimeType || |
---|
3021 | bound.Type == InternalType.MethodGroup || bound.Type == InternalType.AnonymousMethod) |
---|
3022 | return; |
---|
3023 | |
---|
3024 | var a = bounds [index]; |
---|
3025 | if (a == null) { |
---|
3026 | a = new List<BoundInfo> (2); |
---|
3027 | a.Add (bound); |
---|
3028 | bounds [index] = a; |
---|
3029 | return; |
---|
3030 | } |
---|
3031 | |
---|
3032 | if (a.Contains (bound)) |
---|
3033 | return; |
---|
3034 | |
---|
3035 | a.Add (bound); |
---|
3036 | } |
---|
3037 | |
---|
3038 | bool AllTypesAreFixed (TypeSpec[] types) |
---|
3039 | { |
---|
3040 | foreach (TypeSpec t in types) { |
---|
3041 | if (t.IsGenericParameter) { |
---|
3042 | if (!IsFixed (t)) |
---|
3043 | return false; |
---|
3044 | continue; |
---|
3045 | } |
---|
3046 | |
---|
3047 | if (TypeManager.IsGenericType (t)) |
---|
3048 | return AllTypesAreFixed (TypeManager.GetTypeArguments (t)); |
---|
3049 | } |
---|
3050 | |
---|
3051 | return true; |
---|
3052 | } |
---|
3053 | |
---|
3054 | // |
---|
3055 | // 26.3.3.8 Exact Inference |
---|
3056 | // |
---|
3057 | public int ExactInference (TypeSpec u, TypeSpec v) |
---|
3058 | { |
---|
3059 | // If V is an array type |
---|
3060 | if (v.IsArray) { |
---|
3061 | if (!u.IsArray) |
---|
3062 | return 0; |
---|
3063 | |
---|
3064 | var ac_u = (ArrayContainer) u; |
---|
3065 | var ac_v = (ArrayContainer) v; |
---|
3066 | if (ac_u.Rank != ac_v.Rank) |
---|
3067 | return 0; |
---|
3068 | |
---|
3069 | return ExactInference (ac_u.Element, ac_v.Element); |
---|
3070 | } |
---|
3071 | |
---|
3072 | // If V is constructed type and U is constructed type |
---|
3073 | if (TypeManager.IsGenericType (v)) { |
---|
3074 | if (!TypeManager.IsGenericType (u) || v.MemberDefinition != u.MemberDefinition) |
---|
3075 | return 0; |
---|
3076 | |
---|
3077 | TypeSpec [] ga_u = TypeManager.GetTypeArguments (u); |
---|
3078 | TypeSpec [] ga_v = TypeManager.GetTypeArguments (v); |
---|
3079 | if (ga_u.Length != ga_v.Length) |
---|
3080 | return 0; |
---|
3081 | |
---|
3082 | int score = 0; |
---|
3083 | for (int i = 0; i < ga_u.Length; ++i) |
---|
3084 | score += ExactInference (ga_u [i], ga_v [i]); |
---|
3085 | |
---|
3086 | return System.Math.Min (1, score); |
---|
3087 | } |
---|
3088 | |
---|
3089 | // If V is one of the unfixed type arguments |
---|
3090 | int pos = IsUnfixed (v); |
---|
3091 | if (pos == -1) |
---|
3092 | return 0; |
---|
3093 | |
---|
3094 | AddToBounds (new BoundInfo (u, BoundKind.Exact), pos, false); |
---|
3095 | return 1; |
---|
3096 | } |
---|
3097 | |
---|
3098 | public bool FixAllTypes (ResolveContext ec) |
---|
3099 | { |
---|
3100 | for (int i = 0; i < tp_args.Length; ++i) { |
---|
3101 | if (!FixType (ec, i)) |
---|
3102 | return false; |
---|
3103 | } |
---|
3104 | return true; |
---|
3105 | } |
---|
3106 | |
---|
3107 | // |
---|
3108 | // All unfixed type variables Xi are fixed for which all of the following hold: |
---|
3109 | // a, There is at least one type variable Xj that depends on Xi |
---|
3110 | // b, Xi has a non-empty set of bounds |
---|
3111 | // |
---|
3112 | public bool FixDependentTypes (ResolveContext ec, ref bool fixed_any) |
---|
3113 | { |
---|
3114 | for (int i = 0; i < tp_args.Length; ++i) { |
---|
3115 | if (fixed_types[i] != null) |
---|
3116 | continue; |
---|
3117 | |
---|
3118 | if (bounds[i] == null) |
---|
3119 | continue; |
---|
3120 | |
---|
3121 | if (!FixType (ec, i)) |
---|
3122 | return false; |
---|
3123 | |
---|
3124 | fixed_any = true; |
---|
3125 | } |
---|
3126 | |
---|
3127 | return true; |
---|
3128 | } |
---|
3129 | |
---|
3130 | // |
---|
3131 | // All unfixed type variables Xi which depend on no Xj are fixed |
---|
3132 | // |
---|
3133 | public bool FixIndependentTypeArguments (ResolveContext ec, TypeSpec[] methodParameters, ref bool fixed_any) |
---|
3134 | { |
---|
3135 | var types_to_fix = new List<TypeSpec> (tp_args); |
---|
3136 | for (int i = 0; i < methodParameters.Length; ++i) { |
---|
3137 | TypeSpec t = methodParameters[i]; |
---|
3138 | |
---|
3139 | if (!t.IsDelegate) { |
---|
3140 | if (!t.IsExpressionTreeType) |
---|
3141 | continue; |
---|
3142 | |
---|
3143 | t = TypeManager.GetTypeArguments (t) [0]; |
---|
3144 | } |
---|
3145 | |
---|
3146 | if (t.IsGenericParameter) |
---|
3147 | continue; |
---|
3148 | |
---|
3149 | var invoke = Delegate.GetInvokeMethod (t); |
---|
3150 | TypeSpec rtype = invoke.ReturnType; |
---|
3151 | while (rtype.IsArray) |
---|
3152 | rtype = ((ArrayContainer) rtype).Element; |
---|
3153 | |
---|
3154 | if (!rtype.IsGenericParameter && !TypeManager.IsGenericType (rtype)) |
---|
3155 | continue; |
---|
3156 | |
---|
3157 | // Remove dependent types, they cannot be fixed yet |
---|
3158 | RemoveDependentTypes (types_to_fix, rtype); |
---|
3159 | } |
---|
3160 | |
---|
3161 | foreach (TypeSpec t in types_to_fix) { |
---|
3162 | if (t == null) |
---|
3163 | continue; |
---|
3164 | |
---|
3165 | int idx = IsUnfixed (t); |
---|
3166 | if (idx >= 0 && !FixType (ec, idx)) { |
---|
3167 | return false; |
---|
3168 | } |
---|
3169 | } |
---|
3170 | |
---|
3171 | fixed_any = types_to_fix.Count > 0; |
---|
3172 | return true; |
---|
3173 | } |
---|
3174 | |
---|
3175 | // |
---|
3176 | // 26.3.3.10 Fixing |
---|
3177 | // |
---|
3178 | public bool FixType (ResolveContext ec, int i) |
---|
3179 | { |
---|
3180 | // It's already fixed |
---|
3181 | if (fixed_types[i] != null) |
---|
3182 | throw new InternalErrorException ("Type argument has been already fixed"); |
---|
3183 | |
---|
3184 | var candidates = bounds [i]; |
---|
3185 | if (candidates == null) |
---|
3186 | return false; |
---|
3187 | |
---|
3188 | if (candidates.Count == 1) { |
---|
3189 | TypeSpec t = candidates[0].Type; |
---|
3190 | if (t == InternalType.NullLiteral) |
---|
3191 | return false; |
---|
3192 | |
---|
3193 | fixed_types [i] = t; |
---|
3194 | return true; |
---|
3195 | } |
---|
3196 | |
---|
3197 | // |
---|
3198 | // The set of candidate types Uj starts out as the set of |
---|
3199 | // all types in the set of bounds for Xi |
---|
3200 | // |
---|
3201 | var applicable = new bool [candidates.Count]; |
---|
3202 | for (int ci = 0; ci < applicable.Length; ++ci) |
---|
3203 | applicable [ci] = true; |
---|
3204 | |
---|
3205 | for (int ci = 0; ci < applicable.Length; ++ci) { |
---|
3206 | var bound = candidates [ci]; |
---|
3207 | int cii = 0; |
---|
3208 | |
---|
3209 | switch (bound.Kind) { |
---|
3210 | case BoundKind.Exact: |
---|
3211 | for (; cii != applicable.Length; ++cii) { |
---|
3212 | if (ci == cii) |
---|
3213 | continue; |
---|
3214 | |
---|
3215 | if (!applicable[cii]) |
---|
3216 | break; |
---|
3217 | |
---|
3218 | // |
---|
3219 | // For each exact bound U of Xi all types Uj which are not identical |
---|
3220 | // to U are removed from the candidate set |
---|
3221 | // |
---|
3222 | if (candidates [cii].Type != bound.Type) |
---|
3223 | applicable[cii] = false; |
---|
3224 | } |
---|
3225 | |
---|
3226 | break; |
---|
3227 | case BoundKind.Lower: |
---|
3228 | for (; cii != applicable.Length; ++cii) { |
---|
3229 | if (ci == cii) |
---|
3230 | continue; |
---|
3231 | |
---|
3232 | if (!applicable[cii]) |
---|
3233 | break; |
---|
3234 | |
---|
3235 | // |
---|
3236 | // For each lower bound U of Xi all types Uj to which there is not an implicit conversion |
---|
3237 | // from U are removed from the candidate set |
---|
3238 | // |
---|
3239 | if (!Convert.ImplicitConversionExists (ec, bound.GetTypeExpression (), candidates [cii].Type)) { |
---|
3240 | applicable[cii] = false; |
---|
3241 | } |
---|
3242 | } |
---|
3243 | |
---|
3244 | break; |
---|
3245 | |
---|
3246 | case BoundKind.Upper: |
---|
3247 | for (; cii != applicable.Length; ++cii) { |
---|
3248 | if (ci == cii) |
---|
3249 | continue; |
---|
3250 | |
---|
3251 | if (!applicable[cii]) |
---|
3252 | break; |
---|
3253 | |
---|
3254 | // |
---|
3255 | // For each upper bound U of Xi all types Uj from which there is not an implicit conversion |
---|
3256 | // to U are removed from the candidate set |
---|
3257 | // |
---|
3258 | if (!Convert.ImplicitConversionExists (ec, candidates[cii].GetTypeExpression (), bound.Type)) |
---|
3259 | applicable[cii] = false; |
---|
3260 | } |
---|
3261 | |
---|
3262 | break; |
---|
3263 | } |
---|
3264 | } |
---|
3265 | |
---|
3266 | TypeSpec best_candidate = null; |
---|
3267 | for (int ci = 0; ci < applicable.Length; ++ci) { |
---|
3268 | if (!applicable[ci]) |
---|
3269 | continue; |
---|
3270 | |
---|
3271 | var bound = candidates [ci]; |
---|
3272 | if (bound.Type == best_candidate) |
---|
3273 | continue; |
---|
3274 | |
---|
3275 | int cii = 0; |
---|
3276 | for (; cii < applicable.Length; ++cii) { |
---|
3277 | if (ci == cii) |
---|
3278 | continue; |
---|
3279 | |
---|
3280 | if (!applicable[cii]) |
---|
3281 | continue; |
---|
3282 | |
---|
3283 | if (!Convert.ImplicitConversionExists (ec, candidates[cii].GetTypeExpression (), bound.Type)) |
---|
3284 | break; |
---|
3285 | } |
---|
3286 | |
---|
3287 | if (cii != applicable.Length) |
---|
3288 | continue; |
---|
3289 | |
---|
3290 | // |
---|
3291 | // We already have the best candidate, break if it's different (non-unique) |
---|
3292 | // |
---|
3293 | // Dynamic is never ambiguous as we prefer dynamic over other best candidate types |
---|
3294 | // |
---|
3295 | if (best_candidate != null) { |
---|
3296 | |
---|
3297 | if (best_candidate.BuiltinType == BuiltinTypeSpec.Type.Dynamic) |
---|
3298 | continue; |
---|
3299 | |
---|
3300 | if (bound.Type.BuiltinType != BuiltinTypeSpec.Type.Dynamic && best_candidate != bound.Type) |
---|
3301 | return false; |
---|
3302 | } |
---|
3303 | |
---|
3304 | best_candidate = bound.Type; |
---|
3305 | } |
---|
3306 | |
---|
3307 | if (best_candidate == null) |
---|
3308 | return false; |
---|
3309 | |
---|
3310 | fixed_types[i] = best_candidate; |
---|
3311 | return true; |
---|
3312 | } |
---|
3313 | |
---|
3314 | public bool HasBounds (int pos) |
---|
3315 | { |
---|
3316 | return bounds[pos] != null; |
---|
3317 | } |
---|
3318 | |
---|
3319 | // |
---|
3320 | // Uses inferred or partially infered types to inflate delegate type argument. Returns |
---|
3321 | // null when type parameter has not been fixed |
---|
3322 | // |
---|
3323 | public TypeSpec InflateGenericArgument (IModuleContext context, TypeSpec parameter) |
---|
3324 | { |
---|
3325 | var tp = parameter as TypeParameterSpec; |
---|
3326 | if (tp != null) { |
---|
3327 | // |
---|
3328 | // Type inference works on generic arguments (MVAR) only |
---|
3329 | // |
---|
3330 | if (!tp.IsMethodOwned) |
---|
3331 | return parameter; |
---|
3332 | |
---|
3333 | // |
---|
3334 | // Ensure the type parameter belongs to same container |
---|
3335 | // |
---|
3336 | if (tp.DeclaredPosition < tp_args.Length && tp_args[tp.DeclaredPosition] == parameter) |
---|
3337 | return fixed_types[tp.DeclaredPosition] ?? parameter; |
---|
3338 | |
---|
3339 | return parameter; |
---|
3340 | } |
---|
3341 | |
---|
3342 | var gt = parameter as InflatedTypeSpec; |
---|
3343 | if (gt != null) { |
---|
3344 | var inflated_targs = new TypeSpec [gt.TypeArguments.Length]; |
---|
3345 | for (int ii = 0; ii < inflated_targs.Length; ++ii) { |
---|
3346 | var inflated = InflateGenericArgument (context, gt.TypeArguments [ii]); |
---|
3347 | if (inflated == null) |
---|
3348 | return null; |
---|
3349 | |
---|
3350 | inflated_targs[ii] = inflated; |
---|
3351 | } |
---|
3352 | |
---|
3353 | return gt.GetDefinition ().MakeGenericType (context, inflated_targs); |
---|
3354 | } |
---|
3355 | |
---|
3356 | var ac = parameter as ArrayContainer; |
---|
3357 | if (ac != null) { |
---|
3358 | var inflated = InflateGenericArgument (context, ac.Element); |
---|
3359 | if (inflated != ac.Element) |
---|
3360 | return ArrayContainer.MakeType (context.Module, inflated); |
---|
3361 | } |
---|
3362 | |
---|
3363 | return parameter; |
---|
3364 | } |
---|
3365 | |
---|
3366 | // |
---|
3367 | // Tests whether all delegate input arguments are fixed and generic output type |
---|
3368 | // requires output type inference |
---|
3369 | // |
---|
3370 | public bool IsReturnTypeNonDependent (MethodSpec invoke, TypeSpec returnType) |
---|
3371 | { |
---|
3372 | AParametersCollection d_parameters = invoke.Parameters; |
---|
3373 | |
---|
3374 | if (d_parameters.IsEmpty) |
---|
3375 | return true; |
---|
3376 | |
---|
3377 | while (returnType.IsArray) |
---|
3378 | returnType = ((ArrayContainer) returnType).Element; |
---|
3379 | |
---|
3380 | if (returnType.IsGenericParameter) { |
---|
3381 | if (IsFixed (returnType)) |
---|
3382 | return false; |
---|
3383 | } else if (TypeManager.IsGenericType (returnType)) { |
---|
3384 | TypeSpec[] g_args = TypeManager.GetTypeArguments (returnType); |
---|
3385 | |
---|
3386 | // At least one unfixed return type has to exist |
---|
3387 | if (AllTypesAreFixed (g_args)) |
---|
3388 | return false; |
---|
3389 | } else { |
---|
3390 | return false; |
---|
3391 | } |
---|
3392 | |
---|
3393 | // All generic input arguments have to be fixed |
---|
3394 | return AllTypesAreFixed (d_parameters.Types); |
---|
3395 | } |
---|
3396 | |
---|
3397 | bool IsFixed (TypeSpec type) |
---|
3398 | { |
---|
3399 | return IsUnfixed (type) == -1; |
---|
3400 | } |
---|
3401 | |
---|
3402 | int IsUnfixed (TypeSpec type) |
---|
3403 | { |
---|
3404 | if (!type.IsGenericParameter) |
---|
3405 | return -1; |
---|
3406 | |
---|
3407 | for (int i = 0; i < tp_args.Length; ++i) { |
---|
3408 | if (tp_args[i] == type) { |
---|
3409 | if (fixed_types[i] != null) |
---|
3410 | break; |
---|
3411 | |
---|
3412 | return i; |
---|
3413 | } |
---|
3414 | } |
---|
3415 | |
---|
3416 | return -1; |
---|
3417 | } |
---|
3418 | |
---|
3419 | // |
---|
3420 | // 26.3.3.9 Lower-bound Inference |
---|
3421 | // |
---|
3422 | public int LowerBoundInference (TypeSpec u, TypeSpec v) |
---|
3423 | { |
---|
3424 | return LowerBoundInference (u, v, false); |
---|
3425 | } |
---|
3426 | |
---|
3427 | // |
---|
3428 | // Lower-bound (false) or Upper-bound (true) inference based on inversed argument |
---|
3429 | // |
---|
3430 | int LowerBoundInference (TypeSpec u, TypeSpec v, bool inversed) |
---|
3431 | { |
---|
3432 | // If V is one of the unfixed type arguments |
---|
3433 | int pos = IsUnfixed (v); |
---|
3434 | if (pos != -1) { |
---|
3435 | AddToBounds (new BoundInfo (u, inversed ? BoundKind.Upper : BoundKind.Lower), pos, false); |
---|
3436 | return 1; |
---|
3437 | } |
---|
3438 | |
---|
3439 | // If U is an array type |
---|
3440 | var u_ac = u as ArrayContainer; |
---|
3441 | if (u_ac != null) { |
---|
3442 | var v_ac = v as ArrayContainer; |
---|
3443 | if (v_ac != null) { |
---|
3444 | if (u_ac.Rank != v_ac.Rank) |
---|
3445 | return 0; |
---|
3446 | |
---|
3447 | if (TypeSpec.IsValueType (u_ac.Element)) |
---|
3448 | return ExactInference (u_ac.Element, v_ac.Element); |
---|
3449 | |
---|
3450 | return LowerBoundInference (u_ac.Element, v_ac.Element, inversed); |
---|
3451 | } |
---|
3452 | |
---|
3453 | if (u_ac.Rank != 1 || !v.IsArrayGenericInterface) |
---|
3454 | return 0; |
---|
3455 | |
---|
3456 | var v_i = TypeManager.GetTypeArguments (v) [0]; |
---|
3457 | if (TypeSpec.IsValueType (u_ac.Element)) |
---|
3458 | return ExactInference (u_ac.Element, v_i); |
---|
3459 | |
---|
3460 | return LowerBoundInference (u_ac.Element, v_i); |
---|
3461 | } |
---|
3462 | |
---|
3463 | if (v.IsGenericOrParentIsGeneric) { |
---|
3464 | // |
---|
3465 | // if V is a constructed type C<V1..Vk> and there is a unique type C<U1..Uk> |
---|
3466 | // such that U is identical to, inherits from (directly or indirectly), |
---|
3467 | // or implements (directly or indirectly) C<U1..Uk> |
---|
3468 | // |
---|
3469 | var u_candidates = new List<TypeSpec> (); |
---|
3470 | var open_v = v.MemberDefinition; |
---|
3471 | |
---|
3472 | for (TypeSpec t = u; t != null; t = t.BaseType) { |
---|
3473 | if (open_v == t.MemberDefinition) |
---|
3474 | u_candidates.Add (t); |
---|
3475 | |
---|
3476 | // |
---|
3477 | // Using this trick for dynamic type inference, the spec says the type arguments are "unknown" but |
---|
3478 | // that would complicate the process a lot, instead I treat them as dynamic |
---|
3479 | // |
---|
3480 | if (t.BuiltinType == BuiltinTypeSpec.Type.Dynamic) |
---|
3481 | u_candidates.Add (t); |
---|
3482 | } |
---|
3483 | |
---|
3484 | if (u.Interfaces != null) { |
---|
3485 | foreach (var iface in u.Interfaces) { |
---|
3486 | if (open_v == iface.MemberDefinition) |
---|
3487 | u_candidates.Add (iface); |
---|
3488 | } |
---|
3489 | } |
---|
3490 | |
---|
3491 | TypeSpec[] unique_candidate_targs = null; |
---|
3492 | var ga_v = TypeSpec.GetAllTypeArguments (v); |
---|
3493 | foreach (TypeSpec u_candidate in u_candidates) { |
---|
3494 | // |
---|
3495 | // The unique set of types U1..Uk means that if we have an interface I<T>, |
---|
3496 | // class U : I<int>, I<long> then no type inference is made when inferring |
---|
3497 | // type I<T> by applying type U because T could be int or long |
---|
3498 | // |
---|
3499 | if (unique_candidate_targs != null) { |
---|
3500 | TypeSpec[] second_unique_candidate_targs = TypeSpec.GetAllTypeArguments (u_candidate); |
---|
3501 | if (TypeSpecComparer.Equals (unique_candidate_targs, second_unique_candidate_targs)) { |
---|
3502 | unique_candidate_targs = second_unique_candidate_targs; |
---|
3503 | continue; |
---|
3504 | } |
---|
3505 | |
---|
3506 | // |
---|
3507 | // Break when candidate arguments are ambiguous |
---|
3508 | // |
---|
3509 | return 0; |
---|
3510 | } |
---|
3511 | |
---|
3512 | // |
---|
3513 | // A candidate is dynamic type expression, to simplify things use dynamic |
---|
3514 | // for all type parameter of this type. For methods like this one |
---|
3515 | // |
---|
3516 | // void M<T, U> (IList<T>, IList<U[]>) |
---|
3517 | // |
---|
3518 | // dynamic becomes both T and U when the arguments are of dynamic type |
---|
3519 | // |
---|
3520 | if (u_candidate.BuiltinType == BuiltinTypeSpec.Type.Dynamic) { |
---|
3521 | unique_candidate_targs = new TypeSpec[ga_v.Length]; |
---|
3522 | for (int i = 0; i < unique_candidate_targs.Length; ++i) |
---|
3523 | unique_candidate_targs[i] = u_candidate; |
---|
3524 | } else { |
---|
3525 | unique_candidate_targs = TypeSpec.GetAllTypeArguments (u_candidate); |
---|
3526 | } |
---|
3527 | } |
---|
3528 | |
---|
3529 | if (unique_candidate_targs != null) { |
---|
3530 | int score = 0; |
---|
3531 | int tp_index = -1; |
---|
3532 | TypeParameterSpec[] tps = null; |
---|
3533 | |
---|
3534 | for (int i = 0; i < unique_candidate_targs.Length; ++i) { |
---|
3535 | if (tp_index < 0) { |
---|
3536 | while (v.Arity == 0) |
---|
3537 | v = v.DeclaringType; |
---|
3538 | |
---|
3539 | tps = v.MemberDefinition.TypeParameters; |
---|
3540 | tp_index = tps.Length - 1; |
---|
3541 | } |
---|
3542 | |
---|
3543 | Variance variance = tps [tp_index--].Variance; |
---|
3544 | |
---|
3545 | TypeSpec u_i = unique_candidate_targs [i]; |
---|
3546 | if (variance == Variance.None || TypeSpec.IsValueType (u_i)) { |
---|
3547 | if (ExactInference (u_i, ga_v [i]) == 0) |
---|
3548 | ++score; |
---|
3549 | } else { |
---|
3550 | bool upper_bound = (variance == Variance.Contravariant && !inversed) || |
---|
3551 | (variance == Variance.Covariant && inversed); |
---|
3552 | |
---|
3553 | if (LowerBoundInference (u_i, ga_v [i], upper_bound) == 0) |
---|
3554 | ++score; |
---|
3555 | } |
---|
3556 | } |
---|
3557 | |
---|
3558 | return score; |
---|
3559 | } |
---|
3560 | } |
---|
3561 | |
---|
3562 | return 0; |
---|
3563 | } |
---|
3564 | |
---|
3565 | // |
---|
3566 | // 26.3.3.6 Output Type Inference |
---|
3567 | // |
---|
3568 | public int OutputTypeInference (ResolveContext ec, Expression e, TypeSpec t) |
---|
3569 | { |
---|
3570 | // If e is a lambda or anonymous method with inferred return type |
---|
3571 | AnonymousMethodExpression ame = e as AnonymousMethodExpression; |
---|
3572 | if (ame != null) { |
---|
3573 | TypeSpec rt = ame.InferReturnType (ec, this, t); |
---|
3574 | var invoke = Delegate.GetInvokeMethod (t); |
---|
3575 | |
---|
3576 | if (rt == null) { |
---|
3577 | AParametersCollection pd = invoke.Parameters; |
---|
3578 | return ame.Parameters.Count == pd.Count ? 1 : 0; |
---|
3579 | } |
---|
3580 | |
---|
3581 | TypeSpec rtype = invoke.ReturnType; |
---|
3582 | return LowerBoundInference (rt, rtype) + 1; |
---|
3583 | } |
---|
3584 | |
---|
3585 | // |
---|
3586 | // if E is a method group and T is a delegate type or expression tree type |
---|
3587 | // return type Tb with parameter types T1..Tk and return type Tb, and overload |
---|
3588 | // resolution of E with the types T1..Tk yields a single method with return type U, |
---|
3589 | // then a lower-bound inference is made from U for Tb. |
---|
3590 | // |
---|
3591 | if (e is MethodGroupExpr) { |
---|
3592 | if (!t.IsDelegate) { |
---|
3593 | if (!t.IsExpressionTreeType) |
---|
3594 | return 0; |
---|
3595 | |
---|
3596 | t = TypeManager.GetTypeArguments (t)[0]; |
---|
3597 | } |
---|
3598 | |
---|
3599 | var invoke = Delegate.GetInvokeMethod (t); |
---|
3600 | TypeSpec rtype = invoke.ReturnType; |
---|
3601 | |
---|
3602 | if (!IsReturnTypeNonDependent (invoke, rtype)) |
---|
3603 | return 0; |
---|
3604 | |
---|
3605 | // LAMESPEC: Standard does not specify that all methodgroup arguments |
---|
3606 | // has to be fixed but it does not specify how to do recursive type inference |
---|
3607 | // either. We choose the simple option and infer return type only |
---|
3608 | // if all delegate generic arguments are fixed. |
---|
3609 | TypeSpec[] param_types = new TypeSpec [invoke.Parameters.Count]; |
---|
3610 | for (int i = 0; i < param_types.Length; ++i) { |
---|
3611 | var inflated = InflateGenericArgument (ec, invoke.Parameters.Types[i]); |
---|
3612 | if (inflated == null) |
---|
3613 | return 0; |
---|
3614 | |
---|
3615 | param_types[i] = inflated; |
---|
3616 | } |
---|
3617 | |
---|
3618 | MethodGroupExpr mg = (MethodGroupExpr) e; |
---|
3619 | Arguments args = DelegateCreation.CreateDelegateMethodArguments (ec, invoke.Parameters, param_types, e.Location); |
---|
3620 | mg = mg.OverloadResolve (ec, ref args, null, OverloadResolver.Restrictions.CovariantDelegate | OverloadResolver.Restrictions.ProbingOnly); |
---|
3621 | if (mg == null) |
---|
3622 | return 0; |
---|
3623 | |
---|
3624 | return LowerBoundInference (mg.BestCandidateReturnType, rtype) + 1; |
---|
3625 | } |
---|
3626 | |
---|
3627 | // |
---|
3628 | // if e is an expression with type U, then |
---|
3629 | // a lower-bound inference is made from U for T |
---|
3630 | // |
---|
3631 | return LowerBoundInference (e.Type, t) * 2; |
---|
3632 | } |
---|
3633 | |
---|
3634 | void RemoveDependentTypes (List<TypeSpec> types, TypeSpec returnType) |
---|
3635 | { |
---|
3636 | int idx = IsUnfixed (returnType); |
---|
3637 | if (idx >= 0) { |
---|
3638 | types [idx] = null; |
---|
3639 | return; |
---|
3640 | } |
---|
3641 | |
---|
3642 | if (TypeManager.IsGenericType (returnType)) { |
---|
3643 | foreach (TypeSpec t in TypeManager.GetTypeArguments (returnType)) { |
---|
3644 | RemoveDependentTypes (types, t); |
---|
3645 | } |
---|
3646 | } |
---|
3647 | } |
---|
3648 | |
---|
3649 | public bool UnfixedVariableExists { |
---|
3650 | get { |
---|
3651 | foreach (TypeSpec ut in fixed_types) { |
---|
3652 | if (ut == null) |
---|
3653 | return true; |
---|
3654 | } |
---|
3655 | |
---|
3656 | return false; |
---|
3657 | } |
---|
3658 | } |
---|
3659 | } |
---|
3660 | } |
---|