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