1 //
2 // parameter.cs: Parameter definition.
3 //
4 // Author: Miguel de Icaza (miguel@gnu.org)
5 //         Marek Safar (marek.safar@seznam.cz)
6 //
7 // Dual licensed under the terms of the MIT X11 or GNU GPL
8 //
9 // Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
10 // Copyright 2003-2008 Novell, Inc.
11 // Copyright 2011 Xamarin Inc
12 //
13 //
14 using System;
15 using System.Text;
16 
17 #if STATIC
18 using MetaType = IKVM.Reflection.Type;
19 using IKVM.Reflection;
20 using IKVM.Reflection.Emit;
21 #else
22 using MetaType = System.Type;
23 using System.Reflection;
24 using System.Reflection.Emit;
25 #endif
26 
27 namespace Mono.CSharp {
28 
29 	/// <summary>
30 	///   Abstract Base class for parameters of a method.
31 	/// </summary>
32 	public abstract class ParameterBase : Attributable
33 	{
34 		protected ParameterBuilder builder;
35 
ApplyAttributeBuilder(Attribute a, MethodSpec ctor, byte[] cdata, PredefinedAttributes pa)36 		public override void ApplyAttributeBuilder (Attribute a, MethodSpec ctor, byte[] cdata, PredefinedAttributes pa)
37 		{
38 #if false
39 			if (a.Type == pa.MarshalAs) {
40 				UnmanagedMarshal marshal = a.GetMarshal (this);
41 				if (marshal != null) {
42 					builder.SetMarshal (marshal);
43 				}
44 				return;
45 			}
46 #endif
47 			if (a.HasSecurityAttribute) {
48 				a.Error_InvalidSecurityParent ();
49 				return;
50 			}
51 
52 			if (a.Type == pa.Dynamic) {
53 				a.Error_MisusedDynamicAttribute ();
54 				return;
55 			}
56 
57 			builder.SetCustomAttribute ((ConstructorInfo) ctor.GetMetaInfo (), cdata);
58 		}
59 
60 		public ParameterBuilder Builder {
61 			get {
62 				return builder;
63 			}
64 		}
65 
IsClsComplianceRequired()66 		public override bool IsClsComplianceRequired()
67 		{
68 			return false;
69 		}
70 	}
71 
72 	/// <summary>
73 	/// Class for applying custom attributes on the return type
74 	/// </summary>
75 	public class ReturnParameter : ParameterBase
76 	{
77 		MemberCore method;
78 
79 		// TODO: merge method and mb
ReturnParameter(MemberCore method, MethodBuilder mb, Location location)80 		public ReturnParameter (MemberCore method, MethodBuilder mb, Location location)
81 		{
82 			this.method = method;
83 			try {
84 				builder = mb.DefineParameter (0, ParameterAttributes.None, "");
85 			}
86 			catch (ArgumentOutOfRangeException) {
87 				method.Compiler.Report.RuntimeMissingSupport (location, "custom attributes on the return type");
88 			}
89 		}
90 
ApplyAttributeBuilder(Attribute a, MethodSpec ctor, byte[] cdata, PredefinedAttributes pa)91 		public override void ApplyAttributeBuilder (Attribute a, MethodSpec ctor, byte[] cdata, PredefinedAttributes pa)
92 		{
93 			if (a.Type == pa.CLSCompliant) {
94 				method.Compiler.Report.Warning (3023, 1, a.Location,
95 					"CLSCompliant attribute has no meaning when applied to return types. Try putting it on the method instead");
96 			}
97 
98 			// This occurs after Warning -28
99 			if (builder == null)
100 				return;
101 
102 			base.ApplyAttributeBuilder (a, ctor, cdata, pa);
103 		}
104 
105 		public override AttributeTargets AttributeTargets {
106 			get {
107 				return AttributeTargets.ReturnValue;
108 			}
109 		}
110 
111 		/// <summary>
112 		/// Is never called
113 		/// </summary>
114 		public override string[] ValidAttributeTargets {
115 			get {
116 				return null;
117 			}
118 		}
119 	}
120 
121 	public class ImplicitLambdaParameter : Parameter
122 	{
ImplicitLambdaParameter(string name, Location loc)123 		public ImplicitLambdaParameter (string name, Location loc)
124 			: base (null, name, Modifier.NONE, null, loc)
125 		{
126 		}
127 
Resolve(IMemberContext ec, int index)128 		public override TypeSpec Resolve (IMemberContext ec, int index)
129 		{
130 			if (parameter_type == null)
131 				throw new InternalErrorException ("A type of implicit lambda parameter `{0}' is not set",
132 					Name);
133 
134 			base.idx = index;
135 			return parameter_type;
136 		}
137 
SetParameterType(TypeSpec type)138 		public void SetParameterType (TypeSpec type)
139 		{
140 			parameter_type = type;
141 		}
142 	}
143 
144 	public class ParamsParameter : Parameter {
145 
146 		bool ParamsAttributeEmit;
147 
ParamsParameter(FullNamedExpression type, string name, Attributes attrs, Location loc)148 		public ParamsParameter (FullNamedExpression type, string name, Attributes attrs, Location loc):
149 			base (type, name, Parameter.Modifier.PARAMS, attrs, loc)
150 		{
151 		}
152 
Resolve(IMemberContext ec, int index)153 		public override TypeSpec Resolve (IMemberContext ec, int index)
154 		{
155 			if (base.Resolve (ec, index) == null)
156 				return null;
157 
158 			var ac = parameter_type as ArrayContainer;
159 			if (ac == null || ac.Rank != 1) {
160 				ec.Module.Compiler.Report.Error (225, Location, "The params parameter must be a single dimensional array");
161 				return null;
162 			}
163 
164 			var mc = ec as MemberCore;
165 			ParamsAttributeEmit = mc == null || (mc.ModFlags & Modifiers.OVERRIDE) == 0;
166 
167 			return parameter_type;
168 		}
169 
ApplyAttributes(MethodBuilder mb, ConstructorBuilder cb, int index, PredefinedAttributes pa)170 		public override void ApplyAttributes (MethodBuilder mb, ConstructorBuilder cb, int index, PredefinedAttributes pa)
171 		{
172 			base.ApplyAttributes (mb, cb, index, pa);
173 
174 			if (ParamsAttributeEmit)
175 				pa.ParamArray.EmitAttribute (builder);
176 		}
177 	}
178 
179 	public class ArglistParameter : Parameter {
180 		// Doesn't have proper type because it's never chosen for better conversion
ArglistParameter(Location loc)181 		public ArglistParameter (Location loc) :
182 			base (null, String.Empty, Parameter.Modifier.NONE, null, loc)
183 		{
184 			parameter_type = InternalType.Arglist;
185 		}
186 
ApplyAttributes(MethodBuilder mb, ConstructorBuilder cb, int index, PredefinedAttributes pa)187 		public override void  ApplyAttributes (MethodBuilder mb, ConstructorBuilder cb, int index, PredefinedAttributes pa)
188 		{
189 			// Nothing to do
190 		}
191 
CheckAccessibility(InterfaceMemberBase member)192 		public override bool CheckAccessibility (InterfaceMemberBase member)
193 		{
194 			return true;
195 		}
196 
Resolve(IMemberContext ec, int index)197 		public override TypeSpec Resolve (IMemberContext ec, int index)
198 		{
199 			return parameter_type;
200 		}
201 	}
202 
203 	public interface IParameterData
204 	{
205 		Expression DefaultValue { get; }
206 		bool HasExtensionMethodModifier { get; }
207 		bool HasDefaultValue { get; }
208 		Parameter.Modifier ModFlags { get; }
209 		string Name { get; }
210 	}
211 
212 	//
213 	// Parameter information created by parser
214 	//
215 	public class Parameter : ParameterBase, IParameterData, ILocalVariable // TODO: INamedBlockVariable
216 	{
217 		[Flags]
218 		public enum Modifier : byte {
219 			NONE    = 0,
220 			PARAMS  = 1 << 0,
221 			REF = 1 << 1,
222 			OUT = 1 << 2,
223 			This = 1 << 3,
224 			CallerMemberName = 1 << 4,
225 			CallerLineNumber = 1 << 5,
226 			CallerFilePath = 1 << 6,
227 
228 			RefOutMask = REF | OUT,
229 			ModifierMask = PARAMS | REF | OUT | This,
230 			CallerMask = CallerMemberName | CallerLineNumber | CallerFilePath
231 		}
232 
233 		static readonly string[] attribute_targets = new [] { "param" };
234 
235 		FullNamedExpression texpr;
236 		Modifier modFlags;
237 		string name;
238 		Expression default_expr;
239 		protected TypeSpec parameter_type;
240 		readonly Location loc;
241 		protected int idx;
242 		public bool HasAddressTaken;
243 
244 		TemporaryVariableReference expr_tree_variable;
245 
246 		HoistedParameter hoisted_variant;
247 
Parameter(FullNamedExpression type, string name, Modifier mod, Attributes attrs, Location loc)248 		public Parameter (FullNamedExpression type, string name, Modifier mod, Attributes attrs, Location loc)
249 		{
250 			this.name = name;
251 			modFlags = mod;
252 			this.loc = loc;
253 			texpr = type;
254 
255 			// Only assign, attributes will be attached during resolve
256 			base.attributes = attrs;
257 		}
258 
259 		#region Properties
260 
261 		public Expression DefaultExpression {
262 			get {
263 				return default_expr;
264 			}
265 		}
266 
267 		public DefaultParameterValueExpression DefaultValue {
268 			get {
269 				return default_expr as DefaultParameterValueExpression;
270 			}
271 			set {
272 				default_expr = value;
273 			}
274 		}
275 
276 		Expression IParameterData.DefaultValue {
277 			get {
278 				var expr = default_expr as DefaultParameterValueExpression;
279 				return expr == null ? default_expr : expr.Child;
280 			}
281 		}
282 
283 		bool HasOptionalExpression {
284 			get {
285 				return default_expr is DefaultParameterValueExpression;
286 			}
287 		}
288 
289 		public Location Location {
290 			get {
291 				return loc;
292 			}
293 		}
294 
295 		public Modifier ParameterModifier {
296 			get {
297 				return modFlags;
298 			}
299 		}
300 
301 		public TypeSpec Type {
302 			get {
303 				return parameter_type;
304 			}
305 			set {
306 				parameter_type = value;
307 			}
308 		}
309 
310 		public FullNamedExpression TypeExpression  {
311 			get {
312 				return texpr;
313 			}
314 		}
315 
316 		public override string[] ValidAttributeTargets {
317 			get {
318 				return attribute_targets;
319 			}
320 		}
321 
322 		#endregion
323 
ApplyAttributeBuilder(Attribute a, MethodSpec ctor, byte[] cdata, PredefinedAttributes pa)324 		public override void ApplyAttributeBuilder (Attribute a, MethodSpec ctor, byte[] cdata, PredefinedAttributes pa)
325 		{
326 			if (a.Type == pa.In && ModFlags == Modifier.OUT) {
327 				a.Report.Error (36, a.Location, "An out parameter cannot have the `In' attribute");
328 				return;
329 			}
330 
331 			if (a.Type == pa.ParamArray) {
332 				a.Report.Error (674, a.Location, "Do not use `System.ParamArrayAttribute'. Use the `params' keyword instead");
333 				return;
334 			}
335 
336 			if (a.Type == pa.Out && (ModFlags & Modifier.REF) != 0 &&
337 			    !OptAttributes.Contains (pa.In)) {
338 				a.Report.Error (662, a.Location,
339 					"Cannot specify only `Out' attribute on a ref parameter. Use both `In' and `Out' attributes or neither");
340 				return;
341 			}
342 
343 			if (a.Type == pa.CLSCompliant) {
344 				a.Report.Warning (3022, 1, a.Location, "CLSCompliant attribute has no meaning when applied to parameters. Try putting it on the method instead");
345 			} else if (a.Type == pa.DefaultParameterValue || a.Type == pa.OptionalParameter) {
346 				if (HasOptionalExpression) {
347 					a.Report.Error (1745, a.Location,
348 						"Cannot specify `{0}' attribute on optional parameter `{1}'",
349 						a.Type.GetSignatureForError ().Replace ("Attribute", ""), Name);
350 				}
351 
352 				if (a.Type == pa.DefaultParameterValue)
353 					return;
354 			} else if (a.Type == pa.CallerMemberNameAttribute) {
355 				if ((modFlags & Modifier.CallerMemberName) == 0) {
356 					a.Report.Error (4022, a.Location,
357 						"The CallerMemberName attribute can only be applied to parameters with default value");
358 				}
359 			} else if (a.Type == pa.CallerLineNumberAttribute) {
360 				if ((modFlags & Modifier.CallerLineNumber) == 0) {
361 					a.Report.Error (4020, a.Location,
362 						"The CallerLineNumber attribute can only be applied to parameters with default value");
363 				}
364 			} else if (a.Type == pa.CallerFilePathAttribute) {
365 				if ((modFlags & Modifier.CallerFilePath) == 0) {
366 					a.Report.Error (4021, a.Location,
367 						"The CallerFilePath attribute can only be applied to parameters with default value");
368 				}
369 			}
370 
371 			base.ApplyAttributeBuilder (a, ctor, cdata, pa);
372 		}
373 
CheckAccessibility(InterfaceMemberBase member)374 		public virtual bool CheckAccessibility (InterfaceMemberBase member)
375 		{
376 			if (parameter_type == null)
377 				return true;
378 
379 			return member.IsAccessibleAs (parameter_type);
380 		}
381 
IsValidCallerContext(MemberCore memberContext)382 		bool IsValidCallerContext (MemberCore memberContext)
383 		{
384 			var m = memberContext as Method;
385 			if (m != null)
386 				return !m.IsPartialImplementation;
387 
388 			return true;
389 		}
390 
391 		// <summary>
392 		//   Resolve is used in method definitions
393 		// </summary>
Resolve(IMemberContext rc, int index)394 		public virtual TypeSpec Resolve (IMemberContext rc, int index)
395 		{
396 			if (parameter_type != null)
397 				return parameter_type;
398 
399 			if (attributes != null)
400 				attributes.AttachTo (this, rc);
401 
402 			parameter_type = texpr.ResolveAsType (rc);
403 			if (parameter_type == null)
404 				return null;
405 
406 			this.idx = index;
407 
408 			if ((modFlags & Parameter.Modifier.RefOutMask) != 0 && parameter_type.IsSpecialRuntimeType) {
409 				rc.Module.Compiler.Report.Error (1601, Location, "Method or delegate parameter cannot be of type `{0}'",
410 					GetSignatureForError ());
411 				return null;
412 			}
413 
414 			VarianceDecl.CheckTypeVariance (parameter_type,
415 				(modFlags & Parameter.Modifier.RefOutMask) != 0 ? Variance.None : Variance.Contravariant,
416 				rc);
417 
418 			if (parameter_type.IsStatic) {
419 				rc.Module.Compiler.Report.Error (721, Location, "`{0}': static types cannot be used as parameters",
420 					texpr.GetSignatureForError ());
421 				return parameter_type;
422 			}
423 
424 			if ((modFlags & Modifier.This) != 0 && (parameter_type.IsPointer || parameter_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)) {
425 				rc.Module.Compiler.Report.Error (1103, Location, "The extension method cannot be of type `{0}'",
426 					parameter_type.GetSignatureForError ());
427 			}
428 
429 			return parameter_type;
430 		}
431 
ResolveCallerAttributes(ResolveContext rc)432 		void ResolveCallerAttributes (ResolveContext rc)
433 		{
434 			var pa = rc.Module.PredefinedAttributes;
435 			TypeSpec caller_type;
436 			Attribute callerMemberName = null, callerFilePath = null;
437 
438 			foreach (var attr in attributes.Attrs) {
439 				var atype = attr.ResolveTypeForComparison ();
440 				if (atype == null)
441 					continue;
442 
443 				if (atype == pa.CallerMemberNameAttribute) {
444 					caller_type = rc.BuiltinTypes.String;
445 					if (caller_type != parameter_type && !Convert.ImplicitReferenceConversionExists (caller_type, parameter_type)) {
446 						rc.Report.Error (4019, attr.Location,
447 							"The CallerMemberName attribute cannot be applied because there is no standard conversion from `{0}' to `{1}'",
448 							caller_type.GetSignatureForError (), parameter_type.GetSignatureForError ());
449 					}
450 
451 					if (!IsValidCallerContext (rc.CurrentMemberDefinition)) {
452 						rc.Report.Warning (4026, 1, attr.Location,
453 							"The CallerMemberName applied to parameter `{0}' will have no effect because it applies to a member that is used in context that do not allow optional arguments",
454 							name);
455 					}
456 
457 					modFlags |= Modifier.CallerMemberName;
458 					callerMemberName = attr;
459 					continue;
460 				}
461 
462 				if (atype == pa.CallerLineNumberAttribute) {
463 					caller_type = rc.BuiltinTypes.Int;
464 					if (caller_type != parameter_type && !Convert.ImplicitStandardConversionExists (new IntConstant (caller_type, int.MaxValue, Location.Null), parameter_type)) {
465 						rc.Report.Error (4017, attr.Location,
466 							"The CallerLineNumberAttribute attribute cannot be applied because there is no standard conversion from `{0}' to `{1}'",
467 							caller_type.GetSignatureForError (), parameter_type.GetSignatureForError ());
468 					}
469 
470 					if (!IsValidCallerContext (rc.CurrentMemberDefinition)) {
471 						rc.Report.Warning (4024, 1, attr.Location,
472 							"The CallerLineNumberAttribute applied to parameter `{0}' will have no effect because it applies to a member that is used in context that do not allow optional arguments",
473 							name);
474 					}
475 
476 					modFlags |= Modifier.CallerLineNumber;
477 					continue;
478 				}
479 
480 				if (atype == pa.CallerFilePathAttribute) {
481 					caller_type = rc.BuiltinTypes.String;
482 					if (caller_type != parameter_type && !Convert.ImplicitReferenceConversionExists (caller_type, parameter_type)) {
483 						rc.Report.Error (4018, attr.Location,
484 							"The CallerFilePath attribute cannot be applied because there is no standard conversion from `{0}' to `{1}'",
485 							caller_type.GetSignatureForError (), parameter_type.GetSignatureForError ());
486 					}
487 
488 					if (!IsValidCallerContext (rc.CurrentMemberDefinition)) {
489 						rc.Report.Warning (4025, 1, attr.Location,
490 							"The CallerFilePath applied to parameter `{0}' will have no effect because it applies to a member that is used in context that do not allow optional arguments",
491 							name);
492 					}
493 
494 					modFlags |= Modifier.CallerFilePath;
495 					callerFilePath = attr;
496 					continue;
497 				}
498 			}
499 
500 			if ((modFlags & Modifier.CallerLineNumber) != 0) {
501 				if (callerMemberName != null) {
502 					rc.Report.Warning (7081, 1, callerMemberName.Location,
503 						"The CallerMemberNameAttribute applied to parameter `{0}' will have no effect. It is overridden by the CallerLineNumberAttribute",
504 						Name);
505 				}
506 
507 				if (callerFilePath != null) {
508 					rc.Report.Warning (7082, 1, callerFilePath.Location,
509 						"The CallerFilePathAttribute applied to parameter `{0}' will have no effect. It is overridden by the CallerLineNumberAttribute",
510 						name);
511 				}
512 			}
513 
514 			if ((modFlags & Modifier.CallerMemberName) != 0) {
515 				if (callerFilePath != null) {
516 					rc.Report.Warning (7080, 1, callerFilePath.Location,
517 						"The CallerMemberNameAttribute applied to parameter `{0}' will have no effect. It is overridden by the CallerFilePathAttribute",
518 						name);
519 				}
520 
521 			}
522 		}
523 
ResolveDefaultValue(ResolveContext rc)524 		public void ResolveDefaultValue (ResolveContext rc)
525 		{
526 			//
527 			// Default value was specified using an expression
528 			//
529 			if (default_expr != null) {
530 				((DefaultParameterValueExpression)default_expr).Resolve (rc, this);
531 				if (attributes != null)
532 					ResolveCallerAttributes (rc);
533 
534 				return;
535 			}
536 
537 			if (attributes == null)
538 				return;
539 
540 			var pa = rc.Module.PredefinedAttributes;
541 			var def_attr = attributes.Search (pa.DefaultParameterValue);
542 			if (def_attr != null) {
543 				if (def_attr.Resolve () == null)
544 					return;
545 
546 				var default_expr_attr = def_attr.GetParameterDefaultValue ();
547 				if (default_expr_attr == null)
548 					return;
549 
550 				var dpa_rc = def_attr.CreateResolveContext ();
551 				default_expr = default_expr_attr.Resolve (dpa_rc);
552 
553 				if (default_expr is BoxedCast)
554 					default_expr = ((BoxedCast) default_expr).Child;
555 
556 				Constant c = default_expr as Constant;
557 				if (c == null) {
558 					if (parameter_type.BuiltinType == BuiltinTypeSpec.Type.Object) {
559 						rc.Report.Error (1910, default_expr.Location,
560 							"Argument of type `{0}' is not applicable for the DefaultParameterValue attribute",
561 							default_expr.Type.GetSignatureForError ());
562 					} else {
563 						rc.Report.Error (1909, default_expr.Location,
564 							"The DefaultParameterValue attribute is not applicable on parameters of type `{0}'",
565 							default_expr.Type.GetSignatureForError ());
566 					}
567 
568 					default_expr = null;
569 					return;
570 				}
571 
572 				if (TypeSpecComparer.IsEqual (default_expr.Type, parameter_type) ||
573 					(default_expr is NullConstant && TypeSpec.IsReferenceType (parameter_type) && !parameter_type.IsGenericParameter) ||
574 					parameter_type.BuiltinType == BuiltinTypeSpec.Type.Object ||
575 					parameter_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
576 					return;
577 				}
578 
579 				//
580 				// LAMESPEC: Some really weird csc behaviour which we have to mimic
581 				// User operators returning same type as parameter type are considered
582 				// valid for this attribute only
583 				//
584 				// struct S { public static implicit operator S (int i) {} }
585 				//
586 				// void M ([DefaultParameterValue (3)]S s)
587 				//
588 				var expr = Convert.ImplicitUserConversion (dpa_rc, default_expr, parameter_type, loc);
589 				if (expr != null && TypeSpecComparer.IsEqual (expr.Type, parameter_type)) {
590 					return;
591 				}
592 
593 				rc.Report.Error (1908, default_expr.Location, "The type of the default value should match the type of the parameter");
594 				return;
595 			}
596 
597 			var opt_attr = attributes.Search (pa.OptionalParameter);
598 			if (opt_attr != null) {
599 				default_expr = EmptyExpression.MissingValue;
600 			}
601 		}
602 
603 		public bool HasDefaultValue {
604 			get { return default_expr != null; }
605 		}
606 
607 		public bool HasExtensionMethodModifier {
608 			get { return (modFlags & Modifier.This) != 0; }
609 		}
610 
611 		//
612 		// Hoisted parameter variant
613 		//
614 		public HoistedParameter HoistedVariant {
615 			get {
616 				return hoisted_variant;
617 			}
618 			set {
619 				hoisted_variant = value;
620 			}
621 		}
622 
623 		public Modifier ModFlags {
624 			get { return modFlags & ~Modifier.This; }
625 		}
626 
627 		public string Name {
628 			get { return name; }
629 			set { name = value; }
630 		}
631 
632 		public override AttributeTargets AttributeTargets {
633 			get {
634 				return AttributeTargets.Parameter;
635 			}
636 		}
637 
Error_DuplicateName(Report r)638 		public void Error_DuplicateName (Report r)
639 		{
640 			r.Error (100, Location, "The parameter name `{0}' is a duplicate", Name);
641 		}
642 
GetSignatureForError()643 		public virtual string GetSignatureForError ()
644 		{
645 			string type_name;
646 			if (parameter_type != null)
647 				type_name = parameter_type.GetSignatureForError ();
648 			else
649 				type_name = texpr.GetSignatureForError ();
650 
651 			string mod = GetModifierSignature (modFlags);
652 			if (mod.Length > 0)
653 				return String.Concat (mod, " ", type_name);
654 
655 			return type_name;
656 		}
657 
GetModifierSignature(Modifier mod)658 		public static string GetModifierSignature (Modifier mod)
659 		{
660 			switch (mod) {
661 			case Modifier.OUT:
662 				return "out";
663 			case Modifier.PARAMS:
664 				return "params";
665 			case Modifier.REF:
666 				return "ref";
667 			case Modifier.This:
668 				return "this";
669 			default:
670 				return "";
671 			}
672 		}
673 
IsClsCompliant(IMemberContext ctx)674 		public void IsClsCompliant (IMemberContext ctx)
675 		{
676 			if (parameter_type.IsCLSCompliant ())
677 				return;
678 
679 			ctx.Module.Compiler.Report.Warning (3001, 1, Location,
680 				"Argument type `{0}' is not CLS-compliant", parameter_type.GetSignatureForError ());
681 		}
682 
ApplyAttributes(MethodBuilder mb, ConstructorBuilder cb, int index, PredefinedAttributes pa)683 		public virtual void ApplyAttributes (MethodBuilder mb, ConstructorBuilder cb, int index, PredefinedAttributes pa)
684 		{
685 			if (builder != null)
686 				throw new InternalErrorException ("builder already exists");
687 
688 			var pattrs = ParametersCompiled.GetParameterAttribute (modFlags);
689 			if (HasOptionalExpression)
690 				pattrs |= ParameterAttributes.Optional;
691 
692 			if (mb == null)
693 				builder = cb.DefineParameter (index, pattrs, Name);
694 			else
695 				builder = mb.DefineParameter (index, pattrs, Name);
696 
697 			if (OptAttributes != null)
698 				OptAttributes.Emit ();
699 
700 			if (HasDefaultValue && default_expr.Type != null) {
701 				//
702 				// Emit constant values for true constants only, the other
703 				// constant-like expressions will rely on default value expression
704 				//
705 				var def_value = DefaultValue;
706 				Constant c = def_value != null ? def_value.Child as Constant : default_expr as Constant;
707 				if (c != null) {
708 					if (c.Type.BuiltinType == BuiltinTypeSpec.Type.Decimal) {
709 						pa.DecimalConstant.EmitAttribute (builder, (decimal) c.GetValue (), c.Location);
710 					} else {
711 						builder.SetConstant (c.GetValue ());
712 					}
713 				} else if (default_expr.Type.IsStruct || default_expr.Type.IsGenericParameter) {
714 					//
715 					// Handles special case where default expression is used with value-type or type parameter
716 					//
717 					// void Foo (S s = default (S)) {}
718 					//
719 					builder.SetConstant (null);
720 				}
721 			}
722 
723 			if (parameter_type != null) {
724 				if (parameter_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
725 					pa.Dynamic.EmitAttribute (builder);
726 				} else if (parameter_type.HasDynamicElement) {
727 					pa.Dynamic.EmitAttribute (builder, parameter_type, Location);
728 				}
729 
730 				if (parameter_type.HasNamedTupleElement) {
731 					pa.TupleElementNames.EmitAttribute (builder, parameter_type, Location);
732 				}
733 			}
734 		}
735 
Clone()736 		public Parameter Clone ()
737 		{
738 			Parameter p = (Parameter) MemberwiseClone ();
739 			if (attributes != null)
740 				p.attributes = attributes.Clone ();
741 
742 			return p;
743 		}
744 
CreateExpressionTreeVariable(BlockContext ec)745 		public ExpressionStatement CreateExpressionTreeVariable (BlockContext ec)
746 		{
747 			if ((modFlags & Modifier.RefOutMask) != 0)
748 				ec.Report.Error (1951, Location, "An expression tree parameter cannot use `ref' or `out' modifier");
749 
750 			expr_tree_variable = TemporaryVariableReference.Create (ResolveParameterExpressionType (ec, Location).Type, ec.CurrentBlock.ParametersBlock, Location);
751 			expr_tree_variable = (TemporaryVariableReference) expr_tree_variable.Resolve (ec);
752 
753 			Arguments arguments = new Arguments (2);
754 			arguments.Add (new Argument (new TypeOf (parameter_type, Location)));
755 			arguments.Add (new Argument (new StringConstant (ec.BuiltinTypes, Name, Location)));
756 			return new SimpleAssign (ExpressionTreeVariableReference (),
757 				Expression.CreateExpressionFactoryCall (ec, "Parameter", null, arguments, Location));
758 		}
759 
Emit(EmitContext ec)760 		public void Emit (EmitContext ec)
761 		{
762 			ec.EmitArgumentLoad (idx);
763 		}
764 
EmitAssign(EmitContext ec)765 		public void EmitAssign (EmitContext ec)
766 		{
767 			ec.EmitArgumentStore (idx);
768 		}
769 
EmitAddressOf(EmitContext ec)770 		public void EmitAddressOf (EmitContext ec)
771 		{
772 			if ((ModFlags & Modifier.RefOutMask) != 0) {
773 				ec.EmitArgumentLoad (idx);
774 			} else {
775 				ec.EmitArgumentAddress (idx);
776 			}
777 		}
778 
ExpressionTreeVariableReference()779 		public TemporaryVariableReference ExpressionTreeVariableReference ()
780 		{
781 			return expr_tree_variable;
782 		}
783 
784 		//
785 		// System.Linq.Expressions.ParameterExpression type
786 		//
ResolveParameterExpressionType(IMemberContext ec, Location location)787 		public static TypeExpr ResolveParameterExpressionType (IMemberContext ec, Location location)
788 		{
789 			TypeSpec p_type = ec.Module.PredefinedTypes.ParameterExpression.Resolve ();
790 			return new TypeExpression (p_type, location);
791 		}
792 
SetIndex(int index)793 		public void SetIndex (int index)
794 		{
795 			idx = index;
796 		}
797 
Warning_UselessOptionalParameter(Report Report)798 		public void Warning_UselessOptionalParameter (Report Report)
799 		{
800 			Report.Warning (1066, 1, Location,
801 				"The default value specified for optional parameter `{0}' will never be used",
802 				Name);
803 		}
804 	}
805 
806 	//
807 	// Imported or resolved parameter information
808 	//
809 	public class ParameterData : IParameterData
810 	{
811 		readonly string name;
812 		readonly Parameter.Modifier modifiers;
813 		readonly Expression default_value;
814 
ParameterData(string name, Parameter.Modifier modifiers)815 		public ParameterData (string name, Parameter.Modifier modifiers)
816 		{
817 			this.name = name;
818 			this.modifiers = modifiers;
819 		}
820 
ParameterData(string name, Parameter.Modifier modifiers, Expression defaultValue)821 		public ParameterData (string name, Parameter.Modifier modifiers, Expression defaultValue)
822 			: this (name, modifiers)
823 		{
824 			this.default_value = defaultValue;
825 		}
826 
827 		#region IParameterData Members
828 
829 		public Expression DefaultValue {
830 			get { return default_value; }
831 		}
832 
833 		public bool HasExtensionMethodModifier {
834 			get { return (modifiers & Parameter.Modifier.This) != 0; }
835 		}
836 
837 		public bool HasDefaultValue {
838 			get { return default_value != null; }
839 		}
840 
841 		public Parameter.Modifier ModFlags {
842 			get { return modifiers; }
843 		}
844 
845 		public string Name {
846 			get { return name; }
847 		}
848 
849 		#endregion
850 	}
851 
852 	public abstract class AParametersCollection
853 	{
854 		protected bool has_arglist;
855 		protected bool has_params;
856 
857 		// Null object pattern
858 		protected IParameterData [] parameters;
859 		protected TypeSpec [] types;
860 
861 		public CallingConventions CallingConvention {
862 			get {
863 				return has_arglist ?
864 					CallingConventions.VarArgs :
865 					CallingConventions.Standard;
866 			}
867 		}
868 
869 		public int Count {
870 			get { return parameters.Length; }
871 		}
872 
873 		public TypeSpec ExtensionMethodType {
874 			get {
875 				if (Count == 0)
876 					return null;
877 
878 				return FixedParameters [0].HasExtensionMethodModifier ?
879 					types [0] : null;
880 			}
881 		}
882 
883 		public IParameterData [] FixedParameters {
884 			get {
885 				return parameters;
886 			}
887 		}
888 
GetParameterAttribute(Parameter.Modifier modFlags)889 		public static ParameterAttributes GetParameterAttribute (Parameter.Modifier modFlags)
890 		{
891 			return (modFlags & Parameter.Modifier.OUT) != 0 ?
892 				ParameterAttributes.Out : ParameterAttributes.None;
893 		}
894 
895 		// Very expensive operation
GetMetaInfo()896 		public MetaType[] GetMetaInfo ()
897 		{
898 			MetaType[] types;
899 			if (has_arglist) {
900 				if (Count == 1)
901 					return MetaType.EmptyTypes;
902 
903 				types = new MetaType[Count - 1];
904 			} else {
905 				if (Count == 0)
906 					return MetaType.EmptyTypes;
907 
908 				types = new MetaType[Count];
909 			}
910 
911 			for (int i = 0; i < types.Length; ++i) {
912 				types[i] = Types[i].GetMetaInfo ();
913 
914 				if ((FixedParameters[i].ModFlags & Parameter.Modifier.RefOutMask) == 0)
915 					continue;
916 
917 				// TODO MemberCache: Should go to MetaInfo getter
918 				types [i] = types [i].MakeByRefType ();
919 			}
920 
921 			return types;
922 		}
923 
924 		//
925 		// Returns the parameter information based on the name
926 		//
GetParameterIndexByName(string name)927 		public int GetParameterIndexByName (string name)
928 		{
929 			for (int idx = 0; idx < Count; ++idx) {
930 				if (parameters [idx].Name == name)
931 					return idx;
932 			}
933 
934 			return -1;
935 		}
936 
GetSignatureForDocumentation()937 		public string GetSignatureForDocumentation ()
938 		{
939 			if (IsEmpty)
940 				return string.Empty;
941 
942 			StringBuilder sb = new StringBuilder ("(");
943 			for (int i = 0; i < Count; ++i) {
944 				if (i != 0)
945 					sb.Append (",");
946 
947 				sb.Append (types [i].GetSignatureForDocumentation ());
948 
949 				if ((parameters[i].ModFlags & Parameter.Modifier.RefOutMask) != 0)
950 					sb.Append ("@");
951 			}
952 			sb.Append (")");
953 
954 			return sb.ToString ();
955 		}
956 
GetSignatureForError()957 		public string GetSignatureForError ()
958 		{
959 			return GetSignatureForError ("(", ")", Count);
960 		}
961 
GetSignatureForError(string start, string end, int count)962 		public string GetSignatureForError (string start, string end, int count)
963 		{
964 			StringBuilder sb = new StringBuilder (start);
965 			for (int i = 0; i < count; ++i) {
966 				if (i != 0)
967 					sb.Append (", ");
968 				sb.Append (ParameterDesc (i));
969 			}
970 			sb.Append (end);
971 			return sb.ToString ();
972 		}
973 
HasSameParameterDefaults(AParametersCollection a, AParametersCollection b)974 		public static bool HasSameParameterDefaults (AParametersCollection a, AParametersCollection b)
975 		{
976 			if (a == null)
977 				return b == null;
978 
979 			for (int i = 0; i < a.Count; ++i) {
980 				if (a.FixedParameters [i].HasDefaultValue != b.FixedParameters [i].HasDefaultValue)
981 					return false;
982 			}
983 
984 			return true;
985 		}
986 
987 		public bool HasArglist {
988 			get { return has_arglist; }
989 		}
990 
991 		public bool HasExtensionMethodType {
992 			get {
993 				if (Count == 0)
994 					return false;
995 
996 				return FixedParameters [0].HasExtensionMethodModifier;
997 			}
998 		}
999 
1000 		public bool HasParams {
1001 			get { return has_params; }
1002 		}
1003 
1004 		public bool IsEmpty {
1005 			get { return parameters.Length == 0; }
1006 		}
1007 
Inflate(TypeParameterInflator inflator)1008 		public AParametersCollection Inflate (TypeParameterInflator inflator)
1009 		{
1010 			TypeSpec[] inflated_types = null;
1011 			bool default_value = false;
1012 
1013 			for (int i = 0; i < Count; ++i) {
1014 				var inflated_param = inflator.Inflate (types[i]);
1015 				if (inflated_types == null) {
1016 					if (inflated_param == types[i])
1017 						continue;
1018 
1019 					default_value |= FixedParameters[i].HasDefaultValue;
1020 					inflated_types = new TypeSpec[types.Length];
1021 					Array.Copy (types, inflated_types, types.Length);
1022 				} else {
1023 					if (inflated_param == types[i])
1024 						continue;
1025 
1026 					default_value |= FixedParameters[i].HasDefaultValue;
1027 				}
1028 
1029 				inflated_types[i] = inflated_param;
1030 			}
1031 
1032 			if (inflated_types == null)
1033 				return this;
1034 
1035 			var clone = (AParametersCollection) MemberwiseClone ();
1036 			clone.types = inflated_types;
1037 
1038 			//
1039 			// Default expression is original expression from the parameter
1040 			// declaration context which can be of nested enum in generic class type.
1041 			// In such case we end up with expression type of G<T>.E and e.g. parameter
1042 			// type of G<int>.E and conversion would fail without inflate in this
1043 			// context.
1044 			//
1045 			if (default_value) {
1046 				clone.parameters = new IParameterData[Count];
1047 				for (int i = 0; i < Count; ++i) {
1048 					var fp = FixedParameters[i];
1049 					clone.FixedParameters[i] = fp;
1050 
1051 					if (!fp.HasDefaultValue)
1052 						continue;
1053 
1054 					var expr = fp.DefaultValue;
1055 
1056 					if (inflated_types[i] == expr.Type)
1057 						continue;
1058 
1059 					var c = expr as Constant;
1060 					if (c != null) {
1061 						//
1062 						// It may fail we are inflating before type validation is done
1063 						//
1064 						c = Constant.ExtractConstantFromValue (inflated_types[i], c.GetValue (), expr.Location);
1065 						if (c == null)
1066 							expr = new DefaultValueExpression (new TypeExpression (inflated_types[i], expr.Location), expr.Location);
1067 						else
1068 							expr = c;
1069 					} else if (expr is DefaultValueExpression)
1070 						expr = new DefaultValueExpression (new TypeExpression (inflated_types[i], expr.Location), expr.Location);
1071 
1072 					clone.FixedParameters[i] = new ParameterData (fp.Name, fp.ModFlags, expr);
1073 				}
1074 			}
1075 
1076 			return clone;
1077 		}
1078 
ParameterDesc(int pos)1079 		public string ParameterDesc (int pos)
1080 		{
1081 			if (types == null || types [pos] == null)
1082 				return ((Parameter)FixedParameters [pos]).GetSignatureForError ();
1083 
1084 			string type = types [pos].GetSignatureForError ();
1085 			if (FixedParameters [pos].HasExtensionMethodModifier)
1086 				return "this " + type;
1087 
1088 			var mod = FixedParameters[pos].ModFlags & Parameter.Modifier.ModifierMask;
1089 			if (mod == 0)
1090 				return type;
1091 
1092 			return Parameter.GetModifierSignature (mod) + " " + type;
1093 		}
1094 
1095 		public TypeSpec[] Types {
1096 			get { return types; }
1097 			set { types = value; }
1098 		}
1099 	}
1100 
1101 	//
1102 	// A collection of imported or resolved parameters
1103 	//
1104 	public class ParametersImported : AParametersCollection
1105 	{
ParametersImported(IParameterData [] parameters, TypeSpec [] types, bool hasArglist, bool hasParams)1106 		public ParametersImported (IParameterData [] parameters, TypeSpec [] types, bool hasArglist, bool hasParams)
1107 		{
1108 			this.parameters = parameters;
1109 			this.types = types;
1110 			this.has_arglist = hasArglist;
1111 			this.has_params = hasParams;
1112 		}
1113 
ParametersImported(IParameterData[] param, TypeSpec[] types, bool hasParams)1114 		public ParametersImported (IParameterData[] param, TypeSpec[] types, bool hasParams)
1115 		{
1116 			this.parameters = param;
1117 			this.types = types;
1118 			this.has_params = hasParams;
1119 		}
1120 	}
1121 
1122 	/// <summary>
1123 	///   Represents the methods parameters
1124 	/// </summary>
1125 	public class ParametersCompiled : AParametersCollection
1126 	{
1127 		public static readonly ParametersCompiled EmptyReadOnlyParameters = new ParametersCompiled ();
1128 
1129 		// Used by C# 2.0 delegates
1130 		public static readonly ParametersCompiled Undefined = new ParametersCompiled ();
1131 
ParametersCompiled()1132 		private ParametersCompiled ()
1133 		{
1134 			parameters = new Parameter [0];
1135 			types = TypeSpec.EmptyTypes;
1136 		}
1137 
ParametersCompiled(IParameterData[] parameters, TypeSpec[] types)1138 		private ParametersCompiled (IParameterData[] parameters, TypeSpec[] types)
1139 		{
1140 			this.parameters = parameters;
1141 		    this.types = types;
1142 		}
1143 
ParametersCompiled(params Parameter[] parameters)1144 		public ParametersCompiled (params Parameter[] parameters)
1145 		{
1146 			if (parameters == null || parameters.Length == 0)
1147 				throw new ArgumentException ("Use EmptyReadOnlyParameters");
1148 
1149 			this.parameters = parameters;
1150 			int count = parameters.Length;
1151 
1152 			for (int i = 0; i < count; i++){
1153 				has_params |= (parameters [i].ModFlags & Parameter.Modifier.PARAMS) != 0;
1154 			}
1155 		}
1156 
ParametersCompiled(Parameter [] parameters, bool has_arglist)1157 		public ParametersCompiled (Parameter [] parameters, bool has_arglist) :
1158 			this (parameters)
1159 		{
1160 			this.has_arglist = has_arglist;
1161 		}
1162 
CreateFullyResolved(Parameter p, TypeSpec type)1163 		public static ParametersCompiled CreateFullyResolved (Parameter p, TypeSpec type)
1164 		{
1165 			return new ParametersCompiled (new Parameter [] { p }, new TypeSpec [] { type });
1166 		}
1167 
CreateFullyResolved(Parameter[] parameters, TypeSpec[] types)1168 		public static ParametersCompiled CreateFullyResolved (Parameter[] parameters, TypeSpec[] types)
1169 		{
1170 			return new ParametersCompiled (parameters, types);
1171 		}
1172 
Prefix(ParametersCompiled parameters, Parameter p, TypeSpec type)1173 		public static ParametersCompiled Prefix (ParametersCompiled parameters, Parameter p, TypeSpec type)
1174 		{
1175 			var ptypes = new TypeSpec [parameters.Count + 1];
1176 			ptypes [0] = type;
1177 			Array.Copy (parameters.Types, 0, ptypes, 1, parameters.Count);
1178 
1179 			var param = new Parameter [ptypes.Length];
1180 			param [0] = p;
1181 			for (int i = 0; i < parameters.Count; ++i) {
1182 				var pi = parameters [i];
1183 				param [i + 1] = pi;
1184 				pi.SetIndex (i + 1);
1185 			}
1186 
1187 			return ParametersCompiled.CreateFullyResolved (param, ptypes);
1188 		}
1189 
1190 		//
1191 		// TODO: This does not fit here, it should go to different version of AParametersCollection
1192 		// as the underlying type is not Parameter and some methods will fail to cast
1193 		//
CreateFullyResolved(params TypeSpec[] types)1194 		public static AParametersCollection CreateFullyResolved (params TypeSpec[] types)
1195 		{
1196 			var pd = new ParameterData [types.Length];
1197 			for (int i = 0; i < pd.Length; ++i)
1198 				pd[i] = new ParameterData (null, Parameter.Modifier.NONE, null);
1199 
1200 			return new ParametersCompiled (pd, types);
1201 		}
1202 
CreateImplicitParameter(FullNamedExpression texpr, Location loc)1203 		public static ParametersCompiled CreateImplicitParameter (FullNamedExpression texpr, Location loc)
1204 		{
1205 			return new ParametersCompiled (
1206 				new[] { new Parameter (texpr, "value", Parameter.Modifier.NONE, null, loc) },
1207 				null);
1208 		}
1209 
CheckConstraints(IMemberContext mc)1210 		public void CheckConstraints (IMemberContext mc)
1211 		{
1212 			foreach (Parameter p in parameters) {
1213 				//
1214 				// It's null for compiler generated types or special types like __arglist
1215 				//
1216 				if (p.TypeExpression != null)
1217 					ConstraintChecker.Check (mc, p.Type, p.TypeExpression.Location);
1218 			}
1219 		}
1220 
1221 		//
1222 		// Returns non-zero value for equal CLS parameter signatures
1223 		//
IsSameClsSignature(AParametersCollection a, AParametersCollection b)1224 		public static int IsSameClsSignature (AParametersCollection a, AParametersCollection b)
1225 		{
1226 			int res = 0;
1227 
1228 			for (int i = 0; i < a.Count; ++i) {
1229 				var a_type = a.Types[i];
1230 				var b_type = b.Types[i];
1231 				if (TypeSpecComparer.Override.IsEqual (a_type, b_type)) {
1232 					if ((a.FixedParameters[i].ModFlags & Parameter.Modifier.RefOutMask) != (b.FixedParameters[i].ModFlags & Parameter.Modifier.RefOutMask))
1233 						res |= 1;
1234 
1235 					continue;
1236 				}
1237 
1238 				var ac_a = a_type as ArrayContainer;
1239 				if (ac_a == null)
1240 					return 0;
1241 
1242 				var ac_b = b_type as ArrayContainer;
1243 				if (ac_b == null)
1244 					return 0;
1245 
1246 				if (ac_a.Element is ArrayContainer || ac_b.Element is ArrayContainer) {
1247 					res |= 2;
1248 					continue;
1249 				}
1250 
1251 				if (ac_a.Rank != ac_b.Rank && TypeSpecComparer.Override.IsEqual (ac_a.Element, ac_b.Element)) {
1252 					res |= 1;
1253 					continue;
1254 				}
1255 
1256 				return 0;
1257 			}
1258 
1259 			return res;
1260 		}
1261 
MergeGenerated(CompilerContext ctx, ParametersCompiled userParams, bool checkConflicts, Parameter compilerParams, TypeSpec compilerTypes)1262 		public static ParametersCompiled MergeGenerated (CompilerContext ctx, ParametersCompiled userParams, bool checkConflicts, Parameter compilerParams, TypeSpec compilerTypes)
1263 		{
1264 			return MergeGenerated (ctx, userParams, checkConflicts,
1265 				new Parameter [] { compilerParams },
1266 				new TypeSpec [] { compilerTypes });
1267 		}
1268 
1269 		//
1270 		// Use this method when you merge compiler generated parameters with user parameters
1271 		//
MergeGenerated(CompilerContext ctx, ParametersCompiled userParams, bool checkConflicts, Parameter[] compilerParams, TypeSpec[] compilerTypes)1272 		public static ParametersCompiled MergeGenerated (CompilerContext ctx, ParametersCompiled userParams, bool checkConflicts, Parameter[] compilerParams, TypeSpec[] compilerTypes)
1273 		{
1274 			Parameter[] all_params = new Parameter [userParams.Count + compilerParams.Length];
1275 			userParams.FixedParameters.CopyTo(all_params, 0);
1276 
1277 			TypeSpec [] all_types;
1278 			if (userParams.types != null) {
1279 				all_types = new TypeSpec [all_params.Length];
1280 				userParams.Types.CopyTo (all_types, 0);
1281 			} else {
1282 				all_types = null;
1283 			}
1284 
1285 			int last_filled = userParams.Count;
1286 			int index = 0;
1287 			foreach (Parameter p in compilerParams) {
1288 				for (int i = 0; i < last_filled; ++i) {
1289 					while (p.Name == all_params [i].Name) {
1290 						if (checkConflicts && i < userParams.Count) {
1291 							ctx.Report.Error (316, userParams[i].Location,
1292 								"The parameter name `{0}' conflicts with a compiler generated name", p.Name);
1293 						}
1294 						p.Name = '_' + p.Name;
1295 					}
1296 				}
1297 				all_params [last_filled] = p;
1298 				if (all_types != null)
1299 					all_types [last_filled] = compilerTypes [index++];
1300 				++last_filled;
1301 			}
1302 
1303 			ParametersCompiled parameters = new ParametersCompiled (all_params, all_types);
1304 			parameters.has_params = userParams.has_params;
1305 			return parameters;
1306 		}
1307 
1308 		//
1309 		// Parameters checks for members which don't have a block
1310 		//
CheckParameters(MemberCore member)1311 		public void CheckParameters (MemberCore member)
1312 		{
1313 			for (int i = 0; i < parameters.Length; ++i) {
1314 				var name = parameters[i].Name;
1315 				for (int ii = i + 1; ii < parameters.Length; ++ii) {
1316 					if (parameters[ii].Name == name)
1317 						this[ii].Error_DuplicateName (member.Compiler.Report);
1318 				}
1319 			}
1320 		}
1321 
Resolve(IMemberContext ec)1322 		public bool Resolve (IMemberContext ec)
1323 		{
1324 			if (types != null)
1325 				return true;
1326 
1327 			types = new TypeSpec [Count];
1328 
1329 			bool ok = true;
1330 			Parameter p;
1331 			for (int i = 0; i < FixedParameters.Length; ++i) {
1332 				p = this [i];
1333 				TypeSpec t = p.Resolve (ec, i);
1334 				if (t == null) {
1335 					ok = false;
1336 					continue;
1337 				}
1338 
1339 				types [i] = t;
1340 			}
1341 
1342 			return ok;
1343 		}
1344 
ResolveDefaultValues(MemberCore m)1345 		public void ResolveDefaultValues (MemberCore m)
1346 		{
1347 			ResolveContext rc = null;
1348 			for (int i = 0; i < parameters.Length; ++i) {
1349 				Parameter p = (Parameter) parameters [i];
1350 
1351 				if (p.Type != null)
1352 					p.Type.CheckObsoleteness (m, p.Location);
1353 
1354 				//
1355 				// Try not to enter default values resolution if there are is not any default value possible
1356 				//
1357 				if (p.HasDefaultValue || p.OptAttributes != null) {
1358 					if (rc == null)
1359 						rc = new ResolveContext (m);
1360 
1361 					p.ResolveDefaultValue (rc);
1362 				}
1363 			}
1364 		}
1365 
1366 		// Define each type attribute (in/out/ref) and
1367 		// the argument names.
ApplyAttributes(IMemberContext mc, MethodBase builder)1368 		public void ApplyAttributes (IMemberContext mc, MethodBase builder)
1369 		{
1370 			if (Count == 0)
1371 				return;
1372 
1373 			MethodBuilder mb = builder as MethodBuilder;
1374 			ConstructorBuilder cb = builder as ConstructorBuilder;
1375 			var pa = mc.Module.PredefinedAttributes;
1376 
1377 			for (int i = 0; i < Count; i++) {
1378 				this [i].ApplyAttributes (mb, cb, i + 1, pa);
1379 			}
1380 		}
1381 
VerifyClsCompliance(IMemberContext ctx)1382 		public void VerifyClsCompliance (IMemberContext ctx)
1383 		{
1384 			foreach (Parameter p in FixedParameters)
1385 				p.IsClsCompliant (ctx);
1386 		}
1387 
1388 		public Parameter this [int pos] {
1389 			get { return (Parameter) parameters [pos]; }
1390 		}
1391 
CreateExpressionTree(BlockContext ec, Location loc)1392 		public Expression CreateExpressionTree (BlockContext ec, Location loc)
1393 		{
1394 			var initializers = new ArrayInitializer (Count, loc);
1395 			foreach (Parameter p in FixedParameters) {
1396 				//
1397 				// Each parameter expression is stored to local variable
1398 				// to save some memory when referenced later.
1399 				//
1400 				StatementExpression se = new StatementExpression (p.CreateExpressionTreeVariable (ec), Location.Null);
1401 				if (se.Resolve (ec)) {
1402 					ec.CurrentBlock.AddScopeStatement (new TemporaryVariableReference.Declarator (p.ExpressionTreeVariableReference ()));
1403 					ec.CurrentBlock.AddScopeStatement (se);
1404 				}
1405 
1406 				initializers.Add (p.ExpressionTreeVariableReference ());
1407 			}
1408 
1409 			return new ArrayCreation (
1410 				Parameter.ResolveParameterExpressionType (ec, loc),
1411 				initializers, loc);
1412 		}
1413 
Clone()1414 		public ParametersCompiled Clone ()
1415 		{
1416 			ParametersCompiled p = (ParametersCompiled) MemberwiseClone ();
1417 
1418 			p.parameters = new IParameterData [parameters.Length];
1419 			for (int i = 0; i < Count; ++i)
1420 				p.parameters [i] = this [i].Clone ();
1421 
1422 			return p;
1423 		}
1424 	}
1425 
1426 	//
1427 	// Default parameter value expression. We need this wrapper to handle
1428 	// default parameter values of folded constants (e.g. indexer parameters).
1429 	// The expression is resolved only once but applied to two methods which
1430 	// both share reference to this expression and we ensure that resolving
1431 	// this expression always returns same instance
1432 	//
1433 	public class DefaultParameterValueExpression : CompositeExpression
1434 	{
DefaultParameterValueExpression(Expression expr)1435 		public DefaultParameterValueExpression (Expression expr)
1436 			: base (expr)
1437 		{
1438 		}
1439 
Resolve(ResolveContext rc, Parameter p)1440 		public void Resolve (ResolveContext rc, Parameter p)
1441 		{
1442 			var expr = Resolve (rc);
1443 			if (expr == null) {
1444 				this.expr = ErrorExpression.Instance;
1445 				return;
1446 			}
1447 
1448 			expr = Child;
1449 
1450 			if (!(expr is Constant || expr is DefaultValueExpression || expr is DefaultLiteralExpression || (expr is New && ((New) expr).IsGeneratedStructConstructor))) {
1451 				if (!(expr is ErrorExpression)) {
1452 					rc.Report.Error (1736, Location,
1453 						"The expression being assigned to optional parameter `{0}' must be a constant or default value",
1454 						p.Name);
1455 				}
1456 
1457 				return;
1458 			}
1459 
1460 			var parameter_type = p.Type;
1461 			if (type == parameter_type)
1462 				return;
1463 
1464 			var res = Convert.ImplicitConversionStandard (rc, expr, parameter_type, Location);
1465 			if (res != null) {
1466 				if (parameter_type.IsNullableType && res is Nullable.Wrap) {
1467 					Nullable.Wrap wrap = (Nullable.Wrap) res;
1468 					res = wrap.Child;
1469 					if (!(res is Constant)) {
1470 						rc.Report.Error (1770, Location,
1471 							"The expression being assigned to nullable optional parameter `{0}' must be default value",
1472 							p.Name);
1473 						return;
1474 					}
1475 				}
1476 
1477 				if (!expr.IsNull && TypeSpec.IsReferenceType (parameter_type) && parameter_type.BuiltinType != BuiltinTypeSpec.Type.String) {
1478 					rc.Report.Error (1763, Location,
1479 						"Optional parameter `{0}' of type `{1}' can only be initialized with `null'",
1480 						p.Name, parameter_type.GetSignatureForError ());
1481 
1482 					return;
1483 				}
1484 
1485 				this.expr = res;
1486 				return;
1487 			}
1488 
1489 			rc.Report.Error (1750, Location,
1490 				"Optional parameter expression of type `{0}' cannot be converted to parameter type `{1}'",
1491 				type.GetSignatureForError (), parameter_type.GetSignatureForError ());
1492 
1493 			this.expr = ErrorExpression.Instance;
1494 		}
1495 
Accept(StructuralVisitor visitor)1496 		public override object Accept (StructuralVisitor visitor)
1497 		{
1498 			return visitor.Visit (this);
1499 		}
1500 	}
1501 }
1502