/NRefactory/ICSharpCode.NRefactory.CSharp/Parser/mcs/parameter.cs

http://github.com/icsharpcode/ILSpy · C# · 1472 lines · 1104 code · 250 blank · 118 comment · 299 complexity · e6be4bca20fe1faa7ab400d09f4fccc8 MD5 · raw file

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