PageRenderTime 82ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 1ms

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

http://github.com/icsharpcode/ILSpy
C# | 7426 lines | 5229 code | 1239 blank | 958 comment | 1580 complexity | 88c35216da27541d98926645c583efa9 MD5 | raw file
Possible License(s): LGPL-2.1, MIT, CC-BY-SA-3.0
  1. //
  2. // ecore.cs: Core of the Expression representation for the intermediate tree.
  3. //
  4. // Author:
  5. // Miguel de Icaza (miguel@ximian.com)
  6. // Marek Safar (marek.safar@gmail.com)
  7. //
  8. // Copyright 2001, 2002, 2003 Ximian, Inc.
  9. // Copyright 2003-2008 Novell, Inc.
  10. // Copyright 2011-2012 Xamarin Inc.
  11. //
  12. //
  13. using System;
  14. using System.Collections.Generic;
  15. using System.Text;
  16. using SLE = System.Linq.Expressions;
  17. using System.Linq;
  18. #if STATIC
  19. using IKVM.Reflection;
  20. using IKVM.Reflection.Emit;
  21. #else
  22. using System.Reflection;
  23. using System.Reflection.Emit;
  24. #endif
  25. namespace Mono.CSharp {
  26. /// <remarks>
  27. /// The ExprClass class contains the is used to pass the
  28. /// classification of an expression (value, variable, namespace,
  29. /// type, method group, property access, event access, indexer access,
  30. /// nothing).
  31. /// </remarks>
  32. public enum ExprClass : byte {
  33. Unresolved = 0,
  34. Value,
  35. Variable,
  36. Namespace,
  37. Type,
  38. TypeParameter,
  39. MethodGroup,
  40. PropertyAccess,
  41. EventAccess,
  42. IndexerAccess,
  43. Nothing,
  44. }
  45. /// <remarks>
  46. /// This is used to tell Resolve in which types of expressions we're
  47. /// interested.
  48. /// </remarks>
  49. [Flags]
  50. public enum ResolveFlags {
  51. // Returns Value, Variable, PropertyAccess, EventAccess or IndexerAccess.
  52. VariableOrValue = 1,
  53. // Returns a type expression.
  54. Type = 1 << 1,
  55. // Returns a method group.
  56. MethodGroup = 1 << 2,
  57. TypeParameter = 1 << 3,
  58. // Mask of all the expression class flags.
  59. MaskExprClass = VariableOrValue | Type | MethodGroup | TypeParameter,
  60. }
  61. //
  62. // This is just as a hint to AddressOf of what will be done with the
  63. // address.
  64. [Flags]
  65. public enum AddressOp {
  66. Store = 1,
  67. Load = 2,
  68. LoadStore = 3
  69. };
  70. /// <summary>
  71. /// This interface is implemented by variables
  72. /// </summary>
  73. public interface IMemoryLocation {
  74. /// <summary>
  75. /// The AddressOf method should generate code that loads
  76. /// the address of the object and leaves it on the stack.
  77. ///
  78. /// The `mode' argument is used to notify the expression
  79. /// of whether this will be used to read from the address or
  80. /// write to the address.
  81. ///
  82. /// This is just a hint that can be used to provide good error
  83. /// reporting, and should have no other side effects.
  84. /// </summary>
  85. void AddressOf (EmitContext ec, AddressOp mode);
  86. }
  87. //
  88. // An expressions resolved as a direct variable reference
  89. //
  90. public interface IVariableReference : IFixedExpression
  91. {
  92. bool IsHoisted { get; }
  93. string Name { get; }
  94. VariableInfo VariableInfo { get; }
  95. void SetHasAddressTaken ();
  96. }
  97. //
  98. // Implemented by an expression which could be or is always
  99. // fixed
  100. //
  101. public interface IFixedExpression
  102. {
  103. bool IsFixed { get; }
  104. }
  105. public interface IExpressionCleanup
  106. {
  107. void EmitCleanup (EmitContext ec);
  108. }
  109. /// <remarks>
  110. /// Base class for expressions
  111. /// </remarks>
  112. public abstract class Expression {
  113. public ExprClass eclass;
  114. protected TypeSpec type;
  115. protected Location loc;
  116. public TypeSpec Type {
  117. get { return type; }
  118. set { type = value; }
  119. }
  120. public virtual bool IsSideEffectFree {
  121. get {
  122. return false;
  123. }
  124. }
  125. public Location Location {
  126. get { return loc; }
  127. }
  128. public virtual bool IsNull {
  129. get {
  130. return false;
  131. }
  132. }
  133. //
  134. // Used to workaround parser limitation where we cannot get
  135. // start of statement expression location
  136. //
  137. public virtual Location StartLocation {
  138. get {
  139. return loc;
  140. }
  141. }
  142. public virtual MethodGroupExpr CanReduceLambda (AnonymousMethodBody body)
  143. {
  144. //
  145. // Return method-group expression when the expression can be used as
  146. // lambda replacement. A good example is array sorting where instead of
  147. // code like
  148. //
  149. // Array.Sort (s, (a, b) => String.Compare (a, b));
  150. //
  151. // we can use method group directly
  152. //
  153. // Array.Sort (s, String.Compare);
  154. //
  155. // Correct overload will be used because we do the reduction after
  156. // best candidate was found.
  157. //
  158. return null;
  159. }
  160. //
  161. // Returns true when the expression during Emit phase breaks stack
  162. // by using await expression
  163. //
  164. public virtual bool ContainsEmitWithAwait ()
  165. {
  166. return false;
  167. }
  168. /// <summary>
  169. /// Performs semantic analysis on the Expression
  170. /// </summary>
  171. ///
  172. /// <remarks>
  173. /// The Resolve method is invoked to perform the semantic analysis
  174. /// on the node.
  175. ///
  176. /// The return value is an expression (it can be the
  177. /// same expression in some cases) or a new
  178. /// expression that better represents this node.
  179. ///
  180. /// For example, optimizations of Unary (LiteralInt)
  181. /// would return a new LiteralInt with a negated
  182. /// value.
  183. ///
  184. /// If there is an error during semantic analysis,
  185. /// then an error should be reported (using Report)
  186. /// and a null value should be returned.
  187. ///
  188. /// There are two side effects expected from calling
  189. /// Resolve(): the the field variable "eclass" should
  190. /// be set to any value of the enumeration
  191. /// `ExprClass' and the type variable should be set
  192. /// to a valid type (this is the type of the
  193. /// expression).
  194. /// </remarks>
  195. protected abstract Expression DoResolve (ResolveContext rc);
  196. public virtual Expression DoResolveLValue (ResolveContext rc, Expression right_side)
  197. {
  198. return null;
  199. }
  200. //
  201. // This is used if the expression should be resolved as a type or namespace name.
  202. // the default implementation fails.
  203. //
  204. public virtual TypeSpec ResolveAsType (IMemberContext mc, bool allowUnboundTypeArguments = false)
  205. {
  206. ResolveContext ec = new ResolveContext (mc);
  207. Expression e = Resolve (ec);
  208. if (e != null)
  209. e.Error_UnexpectedKind (ec, ResolveFlags.Type, loc);
  210. return null;
  211. }
  212. public static void ErrorIsInaccesible (IMemberContext rc, string member, Location loc)
  213. {
  214. rc.Module.Compiler.Report.Error (122, loc, "`{0}' is inaccessible due to its protection level", member);
  215. }
  216. public void Error_ExpressionMustBeConstant (ResolveContext rc, Location loc, string e_name)
  217. {
  218. rc.Report.Error (133, loc, "The expression being assigned to `{0}' must be constant", e_name);
  219. }
  220. public void Error_ConstantCanBeInitializedWithNullOnly (ResolveContext rc, TypeSpec type, Location loc, string name)
  221. {
  222. rc.Report.Error (134, loc, "A constant `{0}' of reference type `{1}' can only be initialized with null",
  223. name, type.GetSignatureForError ());
  224. }
  225. protected virtual void Error_InvalidExpressionStatement (Report report, Location loc)
  226. {
  227. report.Error (201, loc, "Only assignment, call, increment, decrement, await, and new object expressions can be used as a statement");
  228. }
  229. public void Error_InvalidExpressionStatement (BlockContext bc)
  230. {
  231. Error_InvalidExpressionStatement (bc.Report, loc);
  232. }
  233. public void Error_InvalidExpressionStatement (Report report)
  234. {
  235. Error_InvalidExpressionStatement (report, loc);
  236. }
  237. public static void Error_VoidInvalidInTheContext (Location loc, Report Report)
  238. {
  239. Report.Error (1547, loc, "Keyword `void' cannot be used in this context");
  240. }
  241. public virtual void Error_ValueCannotBeConverted (ResolveContext ec, TypeSpec target, bool expl)
  242. {
  243. Error_ValueCannotBeConvertedCore (ec, loc, target, expl);
  244. }
  245. protected void Error_ValueCannotBeConvertedCore (ResolveContext ec, Location loc, TypeSpec target, bool expl)
  246. {
  247. // The error was already reported as CS1660
  248. if (type == InternalType.AnonymousMethod)
  249. return;
  250. if (type == InternalType.ErrorType || target == InternalType.ErrorType)
  251. return;
  252. string from_type = type.GetSignatureForError ();
  253. string to_type = target.GetSignatureForError ();
  254. if (from_type == to_type) {
  255. from_type = type.GetSignatureForErrorIncludingAssemblyName ();
  256. to_type = target.GetSignatureForErrorIncludingAssemblyName ();
  257. }
  258. if (expl) {
  259. ec.Report.Error (30, loc, "Cannot convert type `{0}' to `{1}'",
  260. from_type, to_type);
  261. return;
  262. }
  263. ec.Report.DisableReporting ();
  264. bool expl_exists = Convert.ExplicitConversion (ec, this, target, Location.Null) != null;
  265. ec.Report.EnableReporting ();
  266. if (expl_exists) {
  267. ec.Report.Error (266, loc,
  268. "Cannot implicitly convert type `{0}' to `{1}'. An explicit conversion exists (are you missing a cast?)",
  269. from_type, to_type);
  270. } else {
  271. ec.Report.Error (29, loc, "Cannot implicitly convert type `{0}' to `{1}'",
  272. from_type, to_type);
  273. }
  274. }
  275. public void Error_TypeArgumentsCannotBeUsed (IMemberContext context, MemberSpec member, Location loc)
  276. {
  277. // Better message for possible generic expressions
  278. if (member != null && (member.Kind & MemberKind.GenericMask) != 0) {
  279. var report = context.Module.Compiler.Report;
  280. report.SymbolRelatedToPreviousError (member);
  281. if (member is TypeSpec)
  282. member = ((TypeSpec) member).GetDefinition ();
  283. else
  284. member = ((MethodSpec) member).GetGenericMethodDefinition ();
  285. string name = member.Kind == MemberKind.Method ? "method" : "type";
  286. if (member.IsGeneric) {
  287. report.Error (305, loc, "Using the generic {0} `{1}' requires `{2}' type argument(s)",
  288. name, member.GetSignatureForError (), member.Arity.ToString ());
  289. } else {
  290. report.Error (308, loc, "The non-generic {0} `{1}' cannot be used with the type arguments",
  291. name, member.GetSignatureForError ());
  292. }
  293. } else {
  294. Error_TypeArgumentsCannotBeUsed (context, ExprClassName, GetSignatureForError (), loc);
  295. }
  296. }
  297. public static void Error_TypeArgumentsCannotBeUsed (IMemberContext context, string exprType, string name, Location loc)
  298. {
  299. context.Module.Compiler.Report.Error (307, loc, "The {0} `{1}' cannot be used with type arguments",
  300. exprType, name);
  301. }
  302. protected virtual void Error_TypeDoesNotContainDefinition (ResolveContext ec, TypeSpec type, string name)
  303. {
  304. Error_TypeDoesNotContainDefinition (ec, loc, type, name);
  305. }
  306. public static void Error_TypeDoesNotContainDefinition (ResolveContext ec, Location loc, TypeSpec type, string name)
  307. {
  308. ec.Report.SymbolRelatedToPreviousError (type);
  309. ec.Report.Error (117, loc, "`{0}' does not contain a definition for `{1}'",
  310. type.GetSignatureForError (), name);
  311. }
  312. public virtual void Error_ValueAssignment (ResolveContext rc, Expression rhs)
  313. {
  314. if (rhs == EmptyExpression.LValueMemberAccess || rhs == EmptyExpression.LValueMemberOutAccess) {
  315. // Already reported as CS1612
  316. } else if (rhs == EmptyExpression.OutAccess) {
  317. rc.Report.Error (1510, loc, "A ref or out argument must be an assignable variable");
  318. } else {
  319. rc.Report.Error (131, loc, "The left-hand side of an assignment must be a variable, a property or an indexer");
  320. }
  321. }
  322. protected void Error_VoidPointerOperation (ResolveContext rc)
  323. {
  324. rc.Report.Error (242, loc, "The operation in question is undefined on void pointers");
  325. }
  326. public static void Warning_UnreachableExpression (ResolveContext rc, Location loc)
  327. {
  328. rc.Report.Warning (429, 4, loc, "Unreachable expression code detected");
  329. }
  330. public ResolveFlags ExprClassToResolveFlags {
  331. get {
  332. switch (eclass) {
  333. case ExprClass.Type:
  334. case ExprClass.Namespace:
  335. return ResolveFlags.Type;
  336. case ExprClass.MethodGroup:
  337. return ResolveFlags.MethodGroup;
  338. case ExprClass.TypeParameter:
  339. return ResolveFlags.TypeParameter;
  340. case ExprClass.Value:
  341. case ExprClass.Variable:
  342. case ExprClass.PropertyAccess:
  343. case ExprClass.EventAccess:
  344. case ExprClass.IndexerAccess:
  345. return ResolveFlags.VariableOrValue;
  346. default:
  347. throw new InternalErrorException (loc.ToString () + " " + GetType () + " ExprClass is Invalid after resolve");
  348. }
  349. }
  350. }
  351. //
  352. // Implements identical simple name and type-name resolution
  353. //
  354. public Expression ProbeIdenticalTypeName (ResolveContext rc, Expression left, SimpleName name)
  355. {
  356. var t = left.Type;
  357. if (t.Kind == MemberKind.InternalCompilerType || t is ElementTypeSpec || t.Arity > 0)
  358. return left;
  359. // In a member access of the form E.I, if E is a single identifier, and if the meaning of E as a simple-name is
  360. // a constant, field, property, local variable, or parameter with the same type as the meaning of E as a type-name
  361. if (left is MemberExpr || left is VariableReference) {
  362. var identical_type = rc.LookupNamespaceOrType (name.Name, 0, LookupMode.Probing, loc) as TypeExpr;
  363. if (identical_type != null && identical_type.Type == left.Type)
  364. return identical_type;
  365. }
  366. return left;
  367. }
  368. public virtual string GetSignatureForError ()
  369. {
  370. return type.GetDefinition ().GetSignatureForError ();
  371. }
  372. public static bool IsNeverNull (Expression expr)
  373. {
  374. if (expr is This || expr is New || expr is ArrayCreation || expr is DelegateCreation || expr is ConditionalMemberAccess)
  375. return true;
  376. var c = expr as Constant;
  377. if (c != null)
  378. return !c.IsNull;
  379. var tc = expr as TypeCast;
  380. if (tc != null)
  381. return IsNeverNull (tc.Child);
  382. return false;
  383. }
  384. protected static bool IsNullPropagatingValid (TypeSpec type)
  385. {
  386. switch (type.Kind) {
  387. case MemberKind.Struct:
  388. return type.IsNullableType;
  389. case MemberKind.Enum:
  390. case MemberKind.Void:
  391. case MemberKind.PointerType:
  392. return false;
  393. case MemberKind.InternalCompilerType:
  394. return type.BuiltinType == BuiltinTypeSpec.Type.Dynamic;
  395. default:
  396. return true;
  397. }
  398. }
  399. public virtual bool HasConditionalAccess ()
  400. {
  401. return false;
  402. }
  403. protected static TypeSpec LiftMemberType (ResolveContext rc, TypeSpec type)
  404. {
  405. return TypeSpec.IsValueType (type) && !type.IsNullableType ?
  406. Nullable.NullableInfo.MakeType (rc.Module, type) :
  407. type;
  408. }
  409. /// <summary>
  410. /// Resolves an expression and performs semantic analysis on it.
  411. /// </summary>
  412. ///
  413. /// <remarks>
  414. /// Currently Resolve wraps DoResolve to perform sanity
  415. /// checking and assertion checking on what we expect from Resolve.
  416. /// </remarks>
  417. public Expression Resolve (ResolveContext ec, ResolveFlags flags)
  418. {
  419. if (eclass != ExprClass.Unresolved) {
  420. if ((flags & ExprClassToResolveFlags) == 0) {
  421. Error_UnexpectedKind (ec, flags, loc);
  422. return null;
  423. }
  424. return this;
  425. }
  426. Expression e;
  427. try {
  428. e = DoResolve (ec);
  429. if (e == null)
  430. return null;
  431. if ((flags & e.ExprClassToResolveFlags) == 0) {
  432. e.Error_UnexpectedKind (ec, flags, loc);
  433. return null;
  434. }
  435. if (e.type == null)
  436. throw new InternalErrorException ("Expression `{0}' didn't set its type in DoResolve", e.GetType ());
  437. return e;
  438. } catch (Exception ex) {
  439. if (loc.IsNull || ec.Module.Compiler.Settings.BreakOnInternalError || ex is CompletionResult || ec.Report.IsDisabled || ex is FatalException ||
  440. ec.Report.Printer is NullReportPrinter)
  441. throw;
  442. ec.Report.Error (584, loc, "Internal compiler error: {0}", ex.Message);
  443. return ErrorExpression.Instance; // TODO: Add location
  444. }
  445. }
  446. /// <summary>
  447. /// Resolves an expression and performs semantic analysis on it.
  448. /// </summary>
  449. public Expression Resolve (ResolveContext rc)
  450. {
  451. return Resolve (rc, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
  452. }
  453. /// <summary>
  454. /// Resolves an expression for LValue assignment
  455. /// </summary>
  456. ///
  457. /// <remarks>
  458. /// Currently ResolveLValue wraps DoResolveLValue to perform sanity
  459. /// checking and assertion checking on what we expect from Resolve
  460. /// </remarks>
  461. public Expression ResolveLValue (ResolveContext ec, Expression right_side)
  462. {
  463. int errors = ec.Report.Errors;
  464. bool out_access = right_side == EmptyExpression.OutAccess;
  465. Expression e = DoResolveLValue (ec, right_side);
  466. if (e != null && out_access && !(e is IMemoryLocation)) {
  467. // FIXME: There's no problem with correctness, the 'Expr = null' handles that.
  468. // Enabling this 'throw' will "only" result in deleting useless code elsewhere,
  469. //throw new InternalErrorException ("ResolveLValue didn't return an IMemoryLocation: " +
  470. // e.GetType () + " " + e.GetSignatureForError ());
  471. e = null;
  472. }
  473. if (e == null) {
  474. if (errors == ec.Report.Errors) {
  475. Error_ValueAssignment (ec, right_side);
  476. }
  477. return null;
  478. }
  479. if (e.eclass == ExprClass.Unresolved)
  480. throw new Exception ("Expression " + e + " ExprClass is Invalid after resolve");
  481. if ((e.type == null) && !(e is GenericTypeExpr))
  482. throw new Exception ("Expression " + e + " did not set its type after Resolve");
  483. return e;
  484. }
  485. public Constant ResolveLabelConstant (ResolveContext rc)
  486. {
  487. var expr = Resolve (rc);
  488. if (expr == null)
  489. return null;
  490. Constant c = expr as Constant;
  491. if (c == null) {
  492. if (expr.type != InternalType.ErrorType)
  493. rc.Report.Error (150, expr.StartLocation, "A constant value is expected");
  494. return null;
  495. }
  496. return c;
  497. }
  498. public virtual void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType, TypeSpec parameterType)
  499. {
  500. if (Attribute.IsValidArgumentType (parameterType)) {
  501. rc.Module.Compiler.Report.Error (182, loc,
  502. "An attribute argument must be a constant expression, typeof expression or array creation expression");
  503. } else {
  504. rc.Module.Compiler.Report.Error (181, loc,
  505. "Attribute constructor parameter has type `{0}', which is not a valid attribute parameter type",
  506. targetType.GetSignatureForError ());
  507. }
  508. }
  509. /// <summary>
  510. /// Emits the code for the expression
  511. /// </summary>
  512. ///
  513. /// <remarks>
  514. /// The Emit method is invoked to generate the code
  515. /// for the expression.
  516. /// </remarks>
  517. public abstract void Emit (EmitContext ec);
  518. // Emit code to branch to @target if this expression is equivalent to @on_true.
  519. // The default implementation is to emit the value, and then emit a brtrue or brfalse.
  520. // Subclasses can provide more efficient implementations, but those MUST be equivalent,
  521. // including the use of conditional branches. Note also that a branch MUST be emitted
  522. public virtual void EmitBranchable (EmitContext ec, Label target, bool on_true)
  523. {
  524. Emit (ec);
  525. ec.Emit (on_true ? OpCodes.Brtrue : OpCodes.Brfalse, target);
  526. }
  527. // Emit this expression for its side effects, not for its value.
  528. // The default implementation is to emit the value, and then throw it away.
  529. // Subclasses can provide more efficient implementations, but those MUST be equivalent
  530. public virtual void EmitSideEffect (EmitContext ec)
  531. {
  532. Emit (ec);
  533. ec.Emit (OpCodes.Pop);
  534. }
  535. //
  536. // Emits the expression into temporary field variable. The method
  537. // should be used for await expressions only
  538. //
  539. public virtual Expression EmitToField (EmitContext ec)
  540. {
  541. //
  542. // This is the await prepare Emit method. When emitting code like
  543. // a + b we emit code like
  544. //
  545. // a.Emit ()
  546. // b.Emit ()
  547. // Opcodes.Add
  548. //
  549. // For await a + await b we have to interfere the flow to keep the
  550. // stack clean because await yields from the expression. The emit
  551. // then changes to
  552. //
  553. // a = a.EmitToField () // a is changed to temporary field access
  554. // b = b.EmitToField ()
  555. // a.Emit ()
  556. // b.Emit ()
  557. // Opcodes.Add
  558. //
  559. //
  560. // The idea is to emit expression and leave the stack empty with
  561. // result value still available.
  562. //
  563. // Expressions should override this default implementation when
  564. // optimized version can be provided (e.g. FieldExpr)
  565. //
  566. //
  567. // We can optimize for side-effect free expressions, they can be
  568. // emitted out of order
  569. //
  570. if (IsSideEffectFree)
  571. return this;
  572. bool needs_temporary = ContainsEmitWithAwait ();
  573. if (!needs_temporary)
  574. ec.EmitThis ();
  575. // Emit original code
  576. var field = EmitToFieldSource (ec);
  577. if (field == null) {
  578. //
  579. // Store the result to temporary field when we
  580. // cannot load `this' directly
  581. //
  582. field = ec.GetTemporaryField (type);
  583. if (needs_temporary) {
  584. //
  585. // Create temporary local (we cannot load `this' before Emit)
  586. //
  587. var temp = ec.GetTemporaryLocal (type);
  588. ec.Emit (OpCodes.Stloc, temp);
  589. ec.EmitThis ();
  590. ec.Emit (OpCodes.Ldloc, temp);
  591. field.EmitAssignFromStack (ec);
  592. ec.FreeTemporaryLocal (temp, type);
  593. } else {
  594. field.EmitAssignFromStack (ec);
  595. }
  596. }
  597. return field;
  598. }
  599. protected virtual FieldExpr EmitToFieldSource (EmitContext ec)
  600. {
  601. //
  602. // Default implementation calls Emit method
  603. //
  604. Emit (ec);
  605. return null;
  606. }
  607. protected static void EmitExpressionsList (EmitContext ec, List<Expression> expressions)
  608. {
  609. if (ec.HasSet (BuilderContext.Options.AsyncBody)) {
  610. bool contains_await = false;
  611. for (int i = 1; i < expressions.Count; ++i) {
  612. if (expressions[i].ContainsEmitWithAwait ()) {
  613. contains_await = true;
  614. break;
  615. }
  616. }
  617. if (contains_await) {
  618. for (int i = 0; i < expressions.Count; ++i) {
  619. expressions[i] = expressions[i].EmitToField (ec);
  620. }
  621. }
  622. }
  623. for (int i = 0; i < expressions.Count; ++i) {
  624. expressions[i].Emit (ec);
  625. }
  626. }
  627. /// <summary>
  628. /// Protected constructor. Only derivate types should
  629. /// be able to be created
  630. /// </summary>
  631. protected Expression ()
  632. {
  633. }
  634. /// <summary>
  635. /// Returns a fully formed expression after a MemberLookup
  636. /// </summary>
  637. ///
  638. static Expression ExprClassFromMemberInfo (MemberSpec spec, Location loc)
  639. {
  640. if (spec is EventSpec)
  641. return new EventExpr ((EventSpec) spec, loc);
  642. if (spec is ConstSpec)
  643. return new ConstantExpr ((ConstSpec) spec, loc);
  644. if (spec is FieldSpec)
  645. return new FieldExpr ((FieldSpec) spec, loc);
  646. if (spec is PropertySpec)
  647. return new PropertyExpr ((PropertySpec) spec, loc);
  648. if (spec is TypeSpec)
  649. return new TypeExpression (((TypeSpec) spec), loc);
  650. return null;
  651. }
  652. public static MethodSpec ConstructorLookup (ResolveContext rc, TypeSpec type, ref Arguments args, Location loc)
  653. {
  654. var ctors = MemberCache.FindMembers (type, Constructor.ConstructorName, true);
  655. if (ctors == null) {
  656. switch (type.Kind) {
  657. case MemberKind.Struct:
  658. rc.Report.SymbolRelatedToPreviousError (type);
  659. // Report meaningful error for struct as they always have default ctor in C# context
  660. OverloadResolver.Error_ConstructorMismatch (rc, type, args == null ? 0 : args.Count, loc);
  661. break;
  662. case MemberKind.MissingType:
  663. case MemberKind.InternalCompilerType:
  664. // LAMESPEC: dynamic is not really object
  665. // if (type.BuiltinType == BuiltinTypeSpec.Type.Object)
  666. // goto default;
  667. break;
  668. default:
  669. rc.Report.SymbolRelatedToPreviousError (type);
  670. rc.Report.Error (143, loc, "The class `{0}' has no constructors defined",
  671. type.GetSignatureForError ());
  672. break;
  673. }
  674. return null;
  675. }
  676. var r = new OverloadResolver (ctors, OverloadResolver.Restrictions.NoBaseMembers, loc);
  677. if (!rc.HasSet (ResolveContext.Options.BaseInitializer)) {
  678. r.InstanceQualifier = new ConstructorInstanceQualifier (type);
  679. }
  680. return r.ResolveMember<MethodSpec> (rc, ref args);
  681. }
  682. [Flags]
  683. public enum MemberLookupRestrictions
  684. {
  685. None = 0,
  686. InvocableOnly = 1,
  687. ExactArity = 1 << 2,
  688. ReadAccess = 1 << 3,
  689. EmptyArguments = 1 << 4,
  690. IgnoreArity = 1 << 5,
  691. IgnoreAmbiguity = 1 << 6
  692. }
  693. //
  694. // Lookup type `queried_type' for code in class `container_type' with a qualifier of
  695. // `qualifier_type' or null to lookup members in the current class.
  696. //
  697. public static Expression MemberLookup (IMemberContext rc, bool errorMode, TypeSpec queried_type, string name, int arity, MemberLookupRestrictions restrictions, Location loc)
  698. {
  699. var members = MemberCache.FindMembers (queried_type, name, false);
  700. if (members == null)
  701. return null;
  702. MemberSpec non_method = null;
  703. MemberSpec ambig_non_method = null;
  704. do {
  705. for (int i = 0; i < members.Count; ++i) {
  706. var member = members[i];
  707. // HACK: for events because +=/-= can appear at same class only, should use OverrideToBase there
  708. if ((member.Modifiers & Modifiers.OVERRIDE) != 0 && member.Kind != MemberKind.Event)
  709. continue;
  710. if ((member.Modifiers & Modifiers.BACKING_FIELD) != 0 || member.Kind == MemberKind.Operator)
  711. continue;
  712. if ((arity > 0 || (restrictions & MemberLookupRestrictions.ExactArity) != 0) && member.Arity != arity)
  713. continue;
  714. if (!errorMode) {
  715. if (!member.IsAccessible (rc))
  716. continue;
  717. //
  718. // With runtime binder we can have a situation where queried type is inaccessible
  719. // because it came via dynamic object, the check about inconsisted accessibility
  720. // had no effect as the type was unknown during compilation
  721. //
  722. // class A {
  723. // private class N { }
  724. //
  725. // public dynamic Foo ()
  726. // {
  727. // return new N ();
  728. // }
  729. // }
  730. //
  731. if (rc.Module.Compiler.IsRuntimeBinder && !member.DeclaringType.IsAccessible (rc))
  732. continue;
  733. }
  734. if ((restrictions & MemberLookupRestrictions.InvocableOnly) != 0) {
  735. if (member is MethodSpec) {
  736. //
  737. // Interface members that are hidden by class members are removed from the set. This
  738. // step only has an effect if T is a type parameter and T has both an effective base
  739. // class other than object and a non-empty effective interface set
  740. //
  741. var tps = queried_type as TypeParameterSpec;
  742. if (tps != null && tps.HasTypeConstraint)
  743. members = RemoveHiddenTypeParameterMethods (members);
  744. return new MethodGroupExpr (members, queried_type, loc);
  745. }
  746. if (!Invocation.IsMemberInvocable (member))
  747. continue;
  748. }
  749. if (non_method == null || member is MethodSpec || non_method.IsNotCSharpCompatible) {
  750. non_method = member;
  751. } else if (!errorMode && !member.IsNotCSharpCompatible) {
  752. //
  753. // Interface members that are hidden by class members are removed from the set when T is a type parameter and
  754. // T has both an effective base class other than object and a non-empty effective interface set.
  755. //
  756. // The spec has more complex rules but we simply remove all members declared in an interface declaration.
  757. //
  758. var tps = queried_type as TypeParameterSpec;
  759. if (tps != null && tps.HasTypeConstraint) {
  760. if (non_method.DeclaringType.IsClass && member.DeclaringType.IsInterface)
  761. continue;
  762. if (non_method.DeclaringType.IsInterface && member.DeclaringType.IsInterface) {
  763. non_method = member;
  764. continue;
  765. }
  766. }
  767. ambig_non_method = member;
  768. }
  769. }
  770. if (non_method != null) {
  771. if (ambig_non_method != null && rc != null && (restrictions & MemberLookupRestrictions.IgnoreAmbiguity) == 0) {
  772. var report = rc.Module.Compiler.Report;
  773. report.SymbolRelatedToPreviousError (non_method);
  774. report.SymbolRelatedToPreviousError (ambig_non_method);
  775. report.Error (229, loc, "Ambiguity between `{0}' and `{1}'",
  776. non_method.GetSignatureForError (), ambig_non_method.GetSignatureForError ());
  777. }
  778. if (non_method is MethodSpec)
  779. return new MethodGroupExpr (members, queried_type, loc);
  780. return ExprClassFromMemberInfo (non_method, loc);
  781. }
  782. if (members[0].DeclaringType.BaseType == null)
  783. members = null;
  784. else
  785. members = MemberCache.FindMembers (members[0].DeclaringType.BaseType, name, false);
  786. } while (members != null);
  787. return null;
  788. }
  789. static IList<MemberSpec> RemoveHiddenTypeParameterMethods (IList<MemberSpec> members)
  790. {
  791. if (members.Count < 2)
  792. return members;
  793. //
  794. // If M is a method, then all non-method members declared in an interface declaration
  795. // are removed from the set, and all methods with the same signature as M declared in
  796. // an interface declaration are removed from the set
  797. //
  798. bool copied = false;
  799. for (int i = 0; i < members.Count; ++i) {
  800. var method = members[i] as MethodSpec;
  801. if (method == null) {
  802. if (!copied) {
  803. copied = true;
  804. members = new List<MemberSpec> (members);
  805. }
  806. members.RemoveAt (i--);
  807. continue;
  808. }
  809. if (!method.DeclaringType.IsInterface)
  810. continue;
  811. for (int ii = 0; ii < members.Count; ++ii) {
  812. var candidate = members[ii] as MethodSpec;
  813. if (candidate == null || !candidate.DeclaringType.IsClass)
  814. continue;
  815. if (!TypeSpecComparer.Override.IsEqual (candidate.Parameters, method.Parameters))
  816. continue;
  817. if (!copied) {
  818. copied = true;
  819. members = new List<MemberSpec> (members);
  820. }
  821. members.RemoveAt (i--);
  822. break;
  823. }
  824. }
  825. return members;
  826. }
  827. protected virtual void Error_NegativeArrayIndex (ResolveContext ec, Location loc)
  828. {
  829. throw new NotImplementedException ();
  830. }
  831. public virtual void Error_OperatorCannotBeApplied (ResolveContext rc, Location loc, string oper, TypeSpec t)
  832. {
  833. if (t == InternalType.ErrorType)
  834. return;
  835. rc.Report.Error (23, loc, "The `{0}' operator cannot be applied to operand of type `{1}'",
  836. oper, t.GetSignatureForError ());
  837. }
  838. protected void Error_PointerInsideExpressionTree (ResolveContext ec)
  839. {
  840. ec.Report.Error (1944, loc, "An expression tree cannot contain an unsafe pointer operation");
  841. }
  842. protected void Error_NullShortCircuitInsideExpressionTree (ResolveContext rc)
  843. {
  844. rc.Report.Error (8072, loc, "An expression tree cannot contain a null propagating operator");
  845. }
  846. public virtual void FlowAnalysis (FlowAnalysisContext fc)
  847. {
  848. }
  849. //
  850. // Special version of flow analysis for expressions which can return different
  851. // on-true and on-false result. Used by &&, ||, ?: expressions
  852. //
  853. public virtual void FlowAnalysisConditional (FlowAnalysisContext fc)
  854. {
  855. FlowAnalysis (fc);
  856. fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse = fc.DefiniteAssignment;
  857. }
  858. /// <summary>
  859. /// Returns an expression that can be used to invoke operator true
  860. /// on the expression if it exists.
  861. /// </summary>
  862. protected static Expression GetOperatorTrue (ResolveContext ec, Expression e, Location loc)
  863. {
  864. return GetOperatorTrueOrFalse (ec, e, true, loc);
  865. }
  866. /// <summary>
  867. /// Returns an expression that can be used to invoke operator false
  868. /// on the expression if it exists.
  869. /// </summary>
  870. protected static Expression GetOperatorFalse (ResolveContext ec, Expression e, Location loc)
  871. {
  872. return GetOperatorTrueOrFalse (ec, e, false, loc);
  873. }
  874. static Expression GetOperatorTrueOrFalse (ResolveContext ec, Expression e, bool is_true, Location loc)
  875. {
  876. var op = is_true ? Operator.OpType.True : Operator.OpType.False;
  877. var methods = MemberCache.GetUserOperator (e.type, op, false);
  878. if (methods == null)
  879. return null;
  880. Arguments arguments = new Arguments (1);
  881. arguments.Add (new Argument (e));
  882. var res = new OverloadResolver (methods, OverloadResolver.Restrictions.BaseMembersIncluded | OverloadResolver.Restrictions.NoBaseMembers, loc);
  883. var oper = res.ResolveOperator (ec, ref arguments);
  884. if (oper == null)
  885. return null;
  886. return new UserOperatorCall (oper, arguments, null, loc);
  887. }
  888. public virtual string ExprClassName
  889. {
  890. get {
  891. switch (eclass){
  892. case ExprClass.Unresolved:
  893. return "Unresolved";
  894. case ExprClass.Value:
  895. return "value";
  896. case ExprClass.Variable:
  897. return "variable";
  898. case ExprClass.Namespace:
  899. return "namespace";
  900. case ExprClass.Type:
  901. return "type";
  902. case ExprClass.MethodGroup:
  903. return "method group";
  904. case ExprClass.PropertyAccess:
  905. return "property access";
  906. case ExprClass.EventAccess:
  907. return "event access";
  908. case ExprClass.IndexerAccess:
  909. return "indexer access";
  910. case ExprClass.Nothing:
  911. return "null";
  912. case ExprClass.TypeParameter:
  913. return "type parameter";
  914. }
  915. throw new Exception ("Should not happen");
  916. }
  917. }
  918. /// <summary>
  919. /// Reports that we were expecting `expr' to be of class `expected'
  920. /// </summary>
  921. public static void Error_UnexpectedKind (IMemberContext ctx, Expression memberExpr, string expected, string was, Location loc)
  922. {
  923. var name = memberExpr.GetSignatureForError ();
  924. ctx.Module.Compiler.Report.Error (118, loc, "`{0}' is a `{1}' but a `{2}' was expected", name, was, expected);
  925. }
  926. public virtual void Error_UnexpectedKind (ResolveContext ec, ResolveFlags flags, Location loc)
  927. {
  928. string [] valid = new string [4];
  929. int count = 0;
  930. if ((flags & ResolveFlags.VariableOrValue) != 0) {
  931. valid [count++] = "variable";
  932. valid [count++] = "value";
  933. }
  934. if ((flags & ResolveFlags.Type) != 0)
  935. valid [count++] = "type";
  936. if ((flags & ResolveFlags.MethodGroup) != 0)
  937. valid [count++] = "method group";
  938. if (count == 0)
  939. valid [count++] = "unknown";
  940. StringBuilder sb = new StringBuilder (valid [0]);
  941. for (int i = 1; i < count - 1; i++) {
  942. sb.Append ("', `");
  943. sb.Append (valid [i]);
  944. }
  945. if (count > 1) {
  946. sb.Append ("' or `");
  947. sb.Append (valid [count - 1]);
  948. }
  949. ec.Report.Error (119, loc,
  950. "Expression denotes a `{0}', where a `{1}' was expected", ExprClassName, sb.ToString ());
  951. }
  952. public static void UnsafeError (ResolveContext ec, Location loc)
  953. {
  954. UnsafeError (ec.Report, loc);
  955. }
  956. public static void UnsafeError (Report Report, Location loc)
  957. {
  958. Report.Error (214, loc, "Pointers and fixed size buffers may only be used in an unsafe context");
  959. }
  960. //
  961. // Converts `source' to an int, uint, long or ulong.
  962. //
  963. protected Expression ConvertExpressionToArrayIndex (ResolveContext ec, Expression source, bool pointerArray = false)
  964. {
  965. var btypes = ec.BuiltinTypes;
  966. if (source.type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
  967. Arguments args = new Arguments (1);
  968. args.Add (new Argument (source));
  969. return new DynamicConversion (btypes.Int, CSharpBinderFlags.ConvertArrayIndex, args, loc).Resolve (ec);
  970. }
  971. Expression converted;
  972. using (ec.Set (ResolveContext.Options.CheckedScope)) {
  973. converted = Convert.ImplicitConversion (ec, source, btypes.Int, source.loc);
  974. if (converted == null)
  975. converted = Convert.ImplicitConversion (ec, source, btypes.UInt, source.loc);
  976. if (converted == null)
  977. converted = Convert.ImplicitConversion (ec, source, btypes.Long, source.loc);
  978. if (converted == null)
  979. converted = Convert.ImplicitConversion (ec, source, btypes.ULong, source.loc);
  980. if (converted == null) {
  981. source.Error_ValueCannotBeConverted (ec, btypes.Int, false);
  982. return null;
  983. }
  984. }
  985. if (pointerArray)
  986. return converted;
  987. //
  988. // Only positive constants are allowed at compile time
  989. //
  990. Constant c = converted as Constant;
  991. if (c != null && c.IsNegative)
  992. Error_NegativeArrayIndex (ec, source.loc);
  993. // No conversion needed to array index
  994. if (converted.Type.BuiltinType == BuiltinTypeSpec.Type.Int)
  995. return converted;
  996. return new ArrayIndexCast (converted, btypes.Int).Resolve (ec);
  997. }
  998. //
  999. // Derived classes implement this method by cloning the fields that
  1000. // could become altered during the Resolve stage
  1001. //
  1002. // Only expressions that are created for the parser need to implement
  1003. // this.
  1004. //
  1005. protected virtual void CloneTo (CloneContext clonectx, Expression target)
  1006. {
  1007. throw new NotImplementedException (
  1008. String.Format (
  1009. "CloneTo not implemented for expression {0}", this.GetType ()));
  1010. }
  1011. //
  1012. // Clones an expression created by the parser.
  1013. //
  1014. // We only support expressions created by the parser so far, not
  1015. // expressions that have been resolved (many more classes would need
  1016. // to implement CloneTo).
  1017. //
  1018. // This infrastructure is here merely for Lambda expressions which
  1019. // compile the same code using different type values for the same
  1020. // arguments to find the correct overload
  1021. //
  1022. public virtual Expression Clone (CloneContext clonectx)
  1023. {
  1024. Expression cloned = (Expression) MemberwiseClone ();
  1025. CloneTo (clonectx, cloned);
  1026. return cloned;
  1027. }
  1028. //
  1029. // Implementation of expression to expression tree conversion
  1030. //
  1031. public abstract Expression CreateExpressionTree (ResolveContext ec);
  1032. protected Expression CreateExpressionFactoryCall (ResolveContext ec, string name, Arguments args)
  1033. {
  1034. return CreateExpressionFactoryCall (ec, name, null, args, loc);
  1035. }
  1036. protected Expression CreateExpressionFactoryCall (ResolveContext ec, string name, TypeArguments typeArguments, Arguments args)
  1037. {
  1038. return CreateExpressionFactoryCall (ec, name, typeArguments, args, loc);
  1039. }
  1040. public static Expression CreateExpressionFactoryCall (ResolveContext ec, string name, TypeArguments typeArguments, Arguments args, Location loc)
  1041. {
  1042. return new Invocation (new MemberAccess (CreateExpressionTypeExpression (ec, loc), name, typeArguments, loc), args);
  1043. }
  1044. protected static TypeExpr CreateExpressionTypeExpression (ResolveContext ec, Location loc)
  1045. {
  1046. var t = ec.Module.PredefinedTypes.Expression.Resolve ();
  1047. if (t == null)
  1048. return null;
  1049. return new TypeExpression (t, loc);
  1050. }
  1051. //
  1052. // Implemented by all expressions which support conversion from
  1053. // compiler expression to invokable runtime expression. Used by
  1054. // dynamic C# binder.
  1055. //
  1056. public virtual SLE.Expression MakeExpression (BuilderContext ctx)
  1057. {
  1058. throw new NotImplementedException ("MakeExpression for " + GetType ());
  1059. }
  1060. public virtual object Accept (StructuralVisitor visitor)
  1061. {
  1062. return visitor.Visit (this);
  1063. }
  1064. }
  1065. /// <summary>
  1066. /// This is just a base class for expressions that can
  1067. /// appear on statements (invocations, object creation,
  1068. /// assignments, post/pre increment and decrement). The idea
  1069. /// being that they would support an extra Emition interface that
  1070. /// does not leave a result on the stack.
  1071. /// </summary>
  1072. public abstract class ExpressionStatement : Expression
  1073. {
  1074. public virtual void MarkReachable (Reachability rc)
  1075. {
  1076. }
  1077. public ExpressionStatement ResolveStatement (BlockContext ec)
  1078. {
  1079. Expression e = Resolve (ec);
  1080. if (e == null)
  1081. return null;
  1082. ExpressionStatement es = e as ExpressionStatement;
  1083. if (es == null || e is AnonymousMethodBody)
  1084. Error_InvalidExpressionStatement (ec);
  1085. //
  1086. // This is quite expensive warning, try to limit the damage
  1087. //
  1088. if (MemberAccess.IsValidDotExpression (e.Type) && !(e is Assign || e is Await)) {
  1089. WarningAsyncWithoutWait (ec, e);
  1090. }
  1091. return es;
  1092. }
  1093. static void WarningAsyncWithoutWait (BlockContext bc, Expression e)
  1094. {
  1095. if (bc.CurrentAnonymousMethod is AsyncInitializer) {
  1096. var awaiter = new AwaitStatement.AwaitableMemberAccess (e) {
  1097. ProbingMode = true
  1098. };
  1099. //
  1100. // Need to do full resolve because GetAwaiter can be extension method
  1101. // available only in this context
  1102. //
  1103. var mg = awaiter.Resolve (bc) as MethodGroupExpr;
  1104. if (mg == null)
  1105. return;
  1106. var arguments = new Arguments (0);
  1107. mg = mg.OverloadResolve (bc, ref arguments, null, OverloadResolver.Restrictions.ProbingOnly);
  1108. if (mg == null)
  1109. return;
  1110. //
  1111. // Use same check rules as for real await
  1112. //
  1113. var awaiter_definition = bc.Module.GetAwaiter (mg.BestCandidateReturnType);
  1114. if (!awaiter_definition.IsValidPattern || !awaiter_definition.INotifyCompletion)
  1115. return;
  1116. bc.Report.Warning (4014, 1, e.Location,
  1117. "The statement is not awaited and execution of current method continues before the call is completed. Consider using `await' operator");
  1118. return;
  1119. }
  1120. var inv = e as Invocation;
  1121. if (inv != null && inv.MethodGroup != null && inv.MethodGroup.BestCandidate.IsAsync) {
  1122. // The warning won't be reported for imported methods to maintain warning compatiblity with csc
  1123. bc.Report.Warning (4014, 1, e.Location,
  1124. "The statement is not awaited and execution of current method continues before the call is completed. Consider using `await' operator or calling `Wait' method");
  1125. return;
  1126. }
  1127. }
  1128. /// <summary>
  1129. /// Requests the expression to be emitted in a `statement'
  1130. /// context. This means that no new value is left on the
  1131. /// stack after invoking this method (constrasted with
  1132. /// Emit that will always leave a value on the stack).
  1133. /// </summary>
  1134. public abstract void EmitStatement (EmitContext ec);
  1135. public override void EmitSideEffect (EmitContext ec)
  1136. {
  1137. EmitStatement (ec);
  1138. }
  1139. }
  1140. /// <summary>
  1141. /// This kind of cast is used to encapsulate the child
  1142. /// whose type is child.Type into an expression that is
  1143. /// reported to return "return_type". This is used to encapsulate
  1144. /// expressions which have compatible types, but need to be dealt
  1145. /// at higher levels with.
  1146. ///
  1147. /// For example, a "byte" expression could be encapsulated in one
  1148. /// of these as an "unsigned int". The type for the expression
  1149. /// would be "unsigned int".
  1150. ///
  1151. /// </summary>
  1152. public abstract class TypeCast : Expression
  1153. {
  1154. protected readonly Expression child;
  1155. protected TypeCast (Expression child, TypeSpec return_type)
  1156. {
  1157. eclass = child.eclass;
  1158. loc = child.Location;
  1159. type = return_type;
  1160. this.child = child;
  1161. }
  1162. public Expression Child {
  1163. get {
  1164. return child;
  1165. }
  1166. }
  1167. public override bool ContainsEmitWithAwait ()
  1168. {
  1169. return child.ContainsEmitWithAwait ();
  1170. }
  1171. public override Expression CreateExpressionTree (ResolveContext ec)
  1172. {
  1173. Arguments args = new Arguments (2);
  1174. args.Add (new Argument (child.CreateExpressionTree (ec)));
  1175. args.Add (new Argument (new TypeOf (type, loc)));
  1176. if (type.IsPointer || child.Type.IsPointer)
  1177. Error_PointerInsideExpressionTree (ec);
  1178. return CreateExpressionFactoryCall (ec, ec.HasSet (ResolveContext.Options.CheckedScope) ? "ConvertChecked" : "Convert", args);
  1179. }
  1180. protected override Expression DoResolve (ResolveContext ec)
  1181. {
  1182. // This should never be invoked, we are born in fully
  1183. // initialized state.
  1184. return this;
  1185. }
  1186. public override void Emit (EmitContext ec)
  1187. {
  1188. child.Emit (ec);
  1189. }
  1190. public override void FlowAnalysis (FlowAnalysisContext fc)
  1191. {
  1192. child.FlowAnalysis (fc);
  1193. }
  1194. public override SLE.Expression MakeExpression (BuilderContext ctx)
  1195. {
  1196. #if STATIC
  1197. return base.MakeExpression (ctx);
  1198. #else
  1199. return ctx.HasSet (BuilderContext.Options.CheckedScope) ?
  1200. SLE.Expression.ConvertChecked (child.MakeExpression (ctx), type.GetMetaInfo ()) :
  1201. SLE.Expression.Convert (child.MakeExpression (ctx), type.GetMetaInfo ());
  1202. #endif
  1203. }
  1204. protected override void CloneTo (CloneContext clonectx, Expression t)
  1205. {
  1206. // Nothing to clone
  1207. }
  1208. public override bool IsNull {
  1209. get { return child.IsNull; }
  1210. }
  1211. }
  1212. public class EmptyCast : TypeCast {
  1213. EmptyCast (Expression child, TypeSpec target_type)
  1214. : base (child, target_type)
  1215. {
  1216. }
  1217. public static Expression Create (Expression child, TypeSpec type)
  1218. {
  1219. Constant c = child as Constant;
  1220. if (c != null) {
  1221. var enum_constant = c as EnumConstant;
  1222. if (enum_constant != null)
  1223. c = enum_constant.Child;
  1224. if (!(c is ReducedExpression.ReducedConstantExpression)) {
  1225. if (c.Type == type)
  1226. return c;
  1227. var res = c.ConvertImplicitly (type);
  1228. if (res != null)
  1229. return res;
  1230. }
  1231. }
  1232. EmptyCast e = child as EmptyCast;
  1233. if (e != null)
  1234. return new EmptyCast (e.child, type);
  1235. return new EmptyCast (child, type);
  1236. }
  1237. public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
  1238. {
  1239. child.EmitBranchable (ec, label, on_true);
  1240. }
  1241. public override void EmitSideEffect (EmitContext ec)
  1242. {
  1243. child.EmitSideEffect (ec);
  1244. }
  1245. }
  1246. //
  1247. // Used for predefined type user operator (no obsolete check, etc.)
  1248. //
  1249. public class OperatorCast : TypeCast
  1250. {
  1251. readonly MethodSpec conversion_operator;
  1252. public OperatorCast (Expression expr, TypeSpec target_type)
  1253. : this (expr, target_type, target_type, false)
  1254. {
  1255. }
  1256. public OperatorCast (Expression expr, TypeSpec target_type, bool find_explicit)
  1257. : this (expr, target_type, target_type, find_explicit)
  1258. {
  1259. }
  1260. public OperatorCast (Expression expr, TypeSpec declaringType, TypeSpec returnType, bool isExplicit)
  1261. : base (expr, returnType)
  1262. {
  1263. var op = isExplicit ? Operator.OpType.Explicit : Operator.OpType.Implicit;
  1264. var mi = MemberCache.GetUserOperator (declaringType, op, true);
  1265. if (mi != null) {
  1266. foreach (MethodSpec oper in mi) {
  1267. if (oper.ReturnType != returnType)
  1268. continue;
  1269. if (oper.Parameters.Types[0] == expr.Type) {
  1270. conversion_operator = oper;
  1271. return;
  1272. }
  1273. }
  1274. }
  1275. throw new InternalErrorException ("Missing predefined user operator between `{0}' and `{1}'",
  1276. returnType.GetSignatureForError (), expr.Type.GetSignatureForError ());
  1277. }
  1278. public override void Emit (EmitContext ec)
  1279. {
  1280. child.Emit (ec);
  1281. ec.Emit (OpCodes.Call, conversion_operator);
  1282. }
  1283. }
  1284. //
  1285. // Constant specialization of EmptyCast.
  1286. // We need to special case this since an empty cast of
  1287. // a constant is still a constant.
  1288. //
  1289. public class EmptyConstantCast : Constant
  1290. {
  1291. public readonly Constant child;
  1292. public EmptyConstantCast (Constant child, TypeSpec type)
  1293. : base (child.Location)
  1294. {
  1295. if (child == null)
  1296. throw new ArgumentNullException ("child");
  1297. this.child = child;
  1298. this.eclass = child.eclass;
  1299. this.type = type;
  1300. }
  1301. public override Constant ConvertExplicitly (bool in_checked_context, TypeSpec target_type)
  1302. {
  1303. if (child.Type == target_type)
  1304. return child;
  1305. // FIXME: check that 'type' can be converted to 'target_type' first
  1306. return child.ConvertExplicitly (in_checked_context, target_type);
  1307. }
  1308. public override Expression CreateExpressionTree (ResolveContext ec)
  1309. {
  1310. Arguments args = Arguments.CreateForExpressionTree (ec, null,
  1311. child.CreateExpressionTree (ec),
  1312. new TypeOf (type, loc));
  1313. if (type.IsPointer)
  1314. Error_PointerInsideExpressionTree (ec);
  1315. return CreateExpressionFactoryCall (ec, "Convert", args);
  1316. }
  1317. public override bool IsDefaultValue {
  1318. get { return child.IsDefaultValue; }
  1319. }
  1320. public override bool IsNegative {
  1321. get { return child.IsNegative; }
  1322. }
  1323. public override bool IsNull {
  1324. get { return child.IsNull; }
  1325. }
  1326. public override bool IsOneInteger {
  1327. get { return child.IsOneInteger; }
  1328. }
  1329. public override bool IsSideEffectFree {
  1330. get {
  1331. return child.IsSideEffectFree;
  1332. }
  1333. }
  1334. public override bool IsZeroInteger {
  1335. get { return child.IsZeroInteger; }
  1336. }
  1337. public override void Emit (EmitContext ec)
  1338. {
  1339. child.Emit (ec);
  1340. }
  1341. public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
  1342. {
  1343. child.EmitBranchable (ec, label, on_true);
  1344. // Only to make verifier happy
  1345. if (TypeManager.IsGenericParameter (type) && child.IsNull)
  1346. ec.Emit (OpCodes.Unbox_Any, type);
  1347. }
  1348. public override void EmitSideEffect (EmitContext ec)
  1349. {
  1350. child.EmitSideEffect (ec);
  1351. }
  1352. public override object GetValue ()
  1353. {
  1354. return child.GetValue ();
  1355. }
  1356. public override string GetValueAsLiteral ()
  1357. {
  1358. return child.GetValueAsLiteral ();
  1359. }
  1360. public override long GetValueAsLong ()
  1361. {
  1362. return child.GetValueAsLong ();
  1363. }
  1364. public override Constant ConvertImplicitly (TypeSpec target_type)
  1365. {
  1366. if (type == target_type)
  1367. return this;
  1368. // FIXME: Do we need to check user conversions?
  1369. if (!Convert.ImplicitStandardConversionExists (this, target_type))
  1370. return null;
  1371. return child.ConvertImplicitly (target_type);
  1372. }
  1373. }
  1374. /// <summary>
  1375. /// This class is used to wrap literals which belong inside Enums
  1376. /// </summary>
  1377. public class EnumConstant : Constant
  1378. {
  1379. public Constant Child;
  1380. public EnumConstant (Constant child, TypeSpec enum_type)
  1381. : base (child.Location)
  1382. {
  1383. this.Child = child;
  1384. this.eclass = ExprClass.Value;
  1385. this.type = enum_type;
  1386. }
  1387. protected EnumConstant (Location loc)
  1388. : base (loc)
  1389. {
  1390. }
  1391. public override void Emit (EmitContext ec)
  1392. {
  1393. Child.Emit (ec);
  1394. }
  1395. public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType, TypeSpec parameterType)
  1396. {
  1397. Child.EncodeAttributeValue (rc, enc, Child.Type, parameterType);
  1398. }
  1399. public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
  1400. {
  1401. Child.EmitBranchable (ec, label, on_true);
  1402. }
  1403. public override void EmitSideEffect (EmitContext ec)
  1404. {
  1405. Child.EmitSideEffect (ec);
  1406. }
  1407. public override string GetSignatureForError()
  1408. {
  1409. return Type.GetSignatureForError ();
  1410. }
  1411. public override object GetValue ()
  1412. {
  1413. return Child.GetValue ();
  1414. }
  1415. #if !STATIC
  1416. public override object GetTypedValue ()
  1417. {
  1418. //
  1419. // The method can be used in dynamic context only (on closed types)
  1420. //
  1421. // System.Enum.ToObject cannot be called on dynamic types
  1422. // EnumBuilder has to be used, but we cannot use EnumBuilder
  1423. // because it does not properly support generics
  1424. //
  1425. return System.Enum.ToObject (type.GetMetaInfo (), Child.GetValue ());
  1426. }
  1427. #endif
  1428. public override string GetValueAsLiteral ()
  1429. {
  1430. return Child.GetValueAsLiteral ();
  1431. }
  1432. public override long GetValueAsLong ()
  1433. {
  1434. return Child.GetValueAsLong ();
  1435. }
  1436. public EnumConstant Increment()
  1437. {
  1438. return new EnumConstant (((IntegralConstant) Child).Increment (), type);
  1439. }
  1440. public override bool IsDefaultValue {
  1441. get {
  1442. return Child.IsDefaultValue;
  1443. }
  1444. }
  1445. public override bool IsSideEffectFree {
  1446. get {
  1447. return Child.IsSideEffectFree;
  1448. }
  1449. }
  1450. public override bool IsZeroInteger {
  1451. get { return Child.IsZeroInteger; }
  1452. }
  1453. public override bool IsNegative {
  1454. get {
  1455. return Child.IsNegative;
  1456. }
  1457. }
  1458. public override Constant ConvertExplicitly (bool in_checked_context, TypeSpec target_type)
  1459. {
  1460. if (Child.Type == target_type)
  1461. return Child;
  1462. return Child.ConvertExplicitly (in_checked_context, target_type);
  1463. }
  1464. public override Constant ConvertImplicitly (TypeSpec type)
  1465. {
  1466. if (this.type == type) {
  1467. return this;
  1468. }
  1469. if (!Convert.ImplicitStandardConversionExists (this, type)){
  1470. return null;
  1471. }
  1472. return Child.ConvertImplicitly (type);
  1473. }
  1474. }
  1475. /// <summary>
  1476. /// This kind of cast is used to encapsulate Value Types in objects.
  1477. ///
  1478. /// The effect of it is to box the value type emitted by the previous
  1479. /// operation.
  1480. /// </summary>
  1481. public class BoxedCast : TypeCast {
  1482. public BoxedCast (Expression expr, TypeSpec target_type)
  1483. : base (expr, target_type)
  1484. {
  1485. eclass = ExprClass.Value;
  1486. }
  1487. protected override Expression DoResolve (ResolveContext ec)
  1488. {
  1489. // This should never be invoked, we are born in fully
  1490. // initialized state.
  1491. return this;
  1492. }
  1493. public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType, TypeSpec parameterType)
  1494. {
  1495. // Only boxing to object type is supported
  1496. if (targetType.BuiltinType != BuiltinTypeSpec.Type.Object) {
  1497. base.EncodeAttributeValue (rc, enc, targetType, parameterType);
  1498. return;
  1499. }
  1500. enc.Encode (child.Type);
  1501. child.EncodeAttributeValue (rc, enc, child.Type, parameterType);
  1502. }
  1503. public override void Emit (EmitContext ec)
  1504. {
  1505. base.Emit (ec);
  1506. ec.Emit (OpCodes.Box, child.Type);
  1507. }
  1508. public override void EmitSideEffect (EmitContext ec)
  1509. {
  1510. // boxing is side-effectful, since it involves runtime checks, except when boxing to Object or ValueType
  1511. // so, we need to emit the box+pop instructions in most cases
  1512. if (child.Type.IsStruct &&
  1513. (type.BuiltinType == BuiltinTypeSpec.Type.Object || type.BuiltinType == BuiltinTypeSpec.Type.ValueType))
  1514. child.EmitSideEffect (ec);
  1515. else
  1516. base.EmitSideEffect (ec);
  1517. }
  1518. }
  1519. public class UnboxCast : TypeCast {
  1520. public UnboxCast (Expression expr, TypeSpec return_type)
  1521. : base (expr, return_type)
  1522. {
  1523. }
  1524. protected override Expression DoResolve (ResolveContext ec)
  1525. {
  1526. // This should never be invoked, we are born in fully
  1527. // initialized state.
  1528. return this;
  1529. }
  1530. public override void Emit (EmitContext ec)
  1531. {
  1532. base.Emit (ec);
  1533. ec.Emit (OpCodes.Unbox_Any, type);
  1534. }
  1535. }
  1536. /// <summary>
  1537. /// This is used to perform explicit numeric conversions.
  1538. ///
  1539. /// Explicit numeric conversions might trigger exceptions in a checked
  1540. /// context, so they should generate the conv.ovf opcodes instead of
  1541. /// conv opcodes.
  1542. /// </summary>
  1543. public class ConvCast : TypeCast {
  1544. public enum Mode : byte {
  1545. I1_U1, I1_U2, I1_U4, I1_U8, I1_CH,
  1546. U1_I1, U1_CH,
  1547. I2_I1, I2_U1, I2_U2, I2_U4, I2_U8, I2_CH,
  1548. U2_I1, U2_U1, U2_I2, U2_CH,
  1549. I4_I1, I4_U1, I4_I2, I4_U2, I4_U4, I4_U8, I4_CH,
  1550. U4_I1, U4_U1, U4_I2, U4_U2, U4_I4, U4_CH,
  1551. I8_I1, I8_U1, I8_I2, I8_U2, I8_I4, I8_U4, I8_U8, I8_CH, I8_I,
  1552. U8_I1, U8_U1, U8_I2, U8_U2, U8_I4, U8_U4, U8_I8, U8_CH, U8_I,
  1553. CH_I1, CH_U1, CH_I2,
  1554. R4_I1, R4_U1, R4_I2, R4_U2, R4_I4, R4_U4, R4_I8, R4_U8, R4_CH,
  1555. R8_I1, R8_U1, R8_I2, R8_U2, R8_I4, R8_U4, R8_I8, R8_U8, R8_CH, R8_R4,
  1556. I_I8,
  1557. }
  1558. Mode mode;
  1559. public ConvCast (Expression child, TypeSpec return_type, Mode m)
  1560. : base (child, return_type)
  1561. {
  1562. mode = m;
  1563. }
  1564. protected override Expression DoResolve (ResolveContext ec)
  1565. {
  1566. // This should never be invoked, we are born in fully
  1567. // initialized state.
  1568. return this;
  1569. }
  1570. public override string ToString ()
  1571. {
  1572. return String.Format ("ConvCast ({0}, {1})", mode, child);
  1573. }
  1574. public override void Emit (EmitContext ec)
  1575. {
  1576. base.Emit (ec);
  1577. Emit (ec, mode);
  1578. }
  1579. public static void Emit (EmitContext ec, Mode mode)
  1580. {
  1581. if (ec.HasSet (EmitContext.Options.CheckedScope)) {
  1582. switch (mode){
  1583. case Mode.I1_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
  1584. case Mode.I1_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
  1585. case Mode.I1_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
  1586. case Mode.I1_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
  1587. case Mode.I1_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
  1588. case Mode.U1_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
  1589. case Mode.U1_CH: /* nothing */ break;
  1590. case Mode.I2_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
  1591. case Mode.I2_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
  1592. case Mode.I2_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
  1593. case Mode.I2_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
  1594. case Mode.I2_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
  1595. case Mode.I2_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
  1596. case Mode.U2_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
  1597. case Mode.U2_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
  1598. case Mode.U2_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
  1599. case Mode.U2_CH: /* nothing */ break;
  1600. case Mode.I4_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
  1601. case Mode.I4_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
  1602. case Mode.I4_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
  1603. case Mode.I4_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
  1604. case Mode.I4_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
  1605. case Mode.I4_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
  1606. case Mode.I4_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
  1607. case Mode.U4_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
  1608. case Mode.U4_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
  1609. case Mode.U4_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
  1610. case Mode.U4_U2: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
  1611. case Mode.U4_I4: ec.Emit (OpCodes.Conv_Ovf_I4_Un); break;
  1612. case Mode.U4_CH: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
  1613. case Mode.I8_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
  1614. case Mode.I8_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
  1615. case Mode.I8_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
  1616. case Mode.I8_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
  1617. case Mode.I8_I4: ec.Emit (OpCodes.Conv_Ovf_I4); break;
  1618. case Mode.I8_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
  1619. case Mode.I8_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
  1620. case Mode.I8_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
  1621. case Mode.I8_I: ec.Emit (OpCodes.Conv_Ovf_U); break;
  1622. case Mode.U8_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
  1623. case Mode.U8_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
  1624. case Mode.U8_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
  1625. case Mode.U8_U2: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
  1626. case Mode.U8_I4: ec.Emit (OpCodes.Conv_Ovf_I4_Un); break;
  1627. case Mode.U8_U4: ec.Emit (OpCodes.Conv_Ovf_U4_Un); break;
  1628. case Mode.U8_I8: ec.Emit (OpCodes.Conv_Ovf_I8_Un); break;
  1629. case Mode.U8_CH: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
  1630. case Mode.U8_I: ec.Emit (OpCodes.Conv_Ovf_U_Un); break;
  1631. case Mode.CH_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
  1632. case Mode.CH_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
  1633. case Mode.CH_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
  1634. case Mode.R4_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
  1635. case Mode.R4_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
  1636. case Mode.R4_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
  1637. case Mode.R4_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
  1638. case Mode.R4_I4: ec.Emit (OpCodes.Conv_Ovf_I4); break;
  1639. case Mode.R4_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
  1640. case Mode.R4_I8: ec.Emit (OpCodes.Conv_Ovf_I8); break;
  1641. case Mode.R4_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
  1642. case Mode.R4_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
  1643. case Mode.R8_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
  1644. case Mode.R8_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
  1645. case Mode.R8_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
  1646. case Mode.R8_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
  1647. case Mode.R8_I4: ec.Emit (OpCodes.Conv_Ovf_I4); break;
  1648. case Mode.R8_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
  1649. case Mode.R8_I8: ec.Emit (OpCodes.Conv_Ovf_I8); break;
  1650. case Mode.R8_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
  1651. case Mode.R8_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
  1652. case Mode.R8_R4: ec.Emit (OpCodes.Conv_R4); break;
  1653. case Mode.I_I8: ec.Emit (OpCodes.Conv_Ovf_I8_Un); break;
  1654. }
  1655. } else {
  1656. switch (mode){
  1657. case Mode.I1_U1: ec.Emit (OpCodes.Conv_U1); break;
  1658. case Mode.I1_U2: ec.Emit (OpCodes.Conv_U2); break;
  1659. case Mode.I1_U4: ec.Emit (OpCodes.Conv_U4); break;
  1660. case Mode.I1_U8: ec.Emit (OpCodes.Conv_I8); break;
  1661. case Mode.I1_CH: ec.Emit (OpCodes.Conv_U2); break;
  1662. case Mode.U1_I1: ec.Emit (OpCodes.Conv_I1); break;
  1663. case Mode.U1_CH: ec.Emit (OpCodes.Conv_U2); break;
  1664. case Mode.I2_I1: ec.Emit (OpCodes.Conv_I1); break;
  1665. case Mode.I2_U1: ec.Emit (OpCodes.Conv_U1); break;
  1666. case Mode.I2_U2: ec.Emit (OpCodes.Conv_U2); break;
  1667. case Mode.I2_U4: ec.Emit (OpCodes.Conv_U4); break;
  1668. case Mode.I2_U8: ec.Emit (OpCodes.Conv_I8); break;
  1669. case Mode.I2_CH: ec.Emit (OpCodes.Conv_U2); break;
  1670. case Mode.U2_I1: ec.Emit (OpCodes.Conv_I1); break;
  1671. case Mode.U2_U1: ec.Emit (OpCodes.Conv_U1); break;
  1672. case Mode.U2_I2: ec.Emit (OpCodes.Conv_I2); break;
  1673. case Mode.U2_CH: /* nothing */ break;
  1674. case Mode.I4_I1: ec.Emit (OpCodes.Conv_I1); break;
  1675. case Mode.I4_U1: ec.Emit (OpCodes.Conv_U1); break;
  1676. case Mode.I4_I2: ec.Emit (OpCodes.Conv_I2); break;
  1677. case Mode.I4_U4: /* nothing */ break;
  1678. case Mode.I4_U2: ec.Emit (OpCodes.Conv_U2); break;
  1679. case Mode.I4_U8: ec.Emit (OpCodes.Conv_I8); break;
  1680. case Mode.I4_CH: ec.Emit (OpCodes.Conv_U2); break;
  1681. case Mode.U4_I1: ec.Emit (OpCodes.Conv_I1); break;
  1682. case Mode.U4_U1: ec.Emit (OpCodes.Conv_U1); break;
  1683. case Mode.U4_I2: ec.Emit (OpCodes.Conv_I2); break;
  1684. case Mode.U4_U2: ec.Emit (OpCodes.Conv_U2); break;
  1685. case Mode.U4_I4: /* nothing */ break;
  1686. case Mode.U4_CH: ec.Emit (OpCodes.Conv_U2); break;
  1687. case Mode.I8_I1: ec.Emit (OpCodes.Conv_I1); break;
  1688. case Mode.I8_U1: ec.Emit (OpCodes.Conv_U1); break;
  1689. case Mode.I8_I2: ec.Emit (OpCodes.Conv_I2); break;
  1690. case Mode.I8_U2: ec.Emit (OpCodes.Conv_U2); break;
  1691. case Mode.I8_I4: ec.Emit (OpCodes.Conv_I4); break;
  1692. case Mode.I8_U4: ec.Emit (OpCodes.Conv_U4); break;
  1693. case Mode.I8_U8: /* nothing */ break;
  1694. case Mode.I8_CH: ec.Emit (OpCodes.Conv_U2); break;
  1695. case Mode.I8_I: ec.Emit (OpCodes.Conv_U); break;
  1696. case Mode.U8_I1: ec.Emit (OpCodes.Conv_I1); break;
  1697. case Mode.U8_U1: ec.Emit (OpCodes.Conv_U1); break;
  1698. case Mode.U8_I2: ec.Emit (OpCodes.Conv_I2); break;
  1699. case Mode.U8_U2: ec.Emit (OpCodes.Conv_U2); break;
  1700. case Mode.U8_I4: ec.Emit (OpCodes.Conv_I4); break;
  1701. case Mode.U8_U4: ec.Emit (OpCodes.Conv_U4); break;
  1702. case Mode.U8_I8: /* nothing */ break;
  1703. case Mode.U8_CH: ec.Emit (OpCodes.Conv_U2); break;
  1704. case Mode.U8_I: ec.Emit (OpCodes.Conv_U); break;
  1705. case Mode.CH_I1: ec.Emit (OpCodes.Conv_I1); break;
  1706. case Mode.CH_U1: ec.Emit (OpCodes.Conv_U1); break;
  1707. case Mode.CH_I2: ec.Emit (OpCodes.Conv_I2); break;
  1708. case Mode.R4_I1: ec.Emit (OpCodes.Conv_I1); break;
  1709. case Mode.R4_U1: ec.Emit (OpCodes.Conv_U1); break;
  1710. case Mode.R4_I2: ec.Emit (OpCodes.Conv_I2); break;
  1711. case Mode.R4_U2: ec.Emit (OpCodes.Conv_U2); break;
  1712. case Mode.R4_I4: ec.Emit (OpCodes.Conv_I4); break;
  1713. case Mode.R4_U4: ec.Emit (OpCodes.Conv_U4); break;
  1714. case Mode.R4_I8: ec.Emit (OpCodes.Conv_I8); break;
  1715. case Mode.R4_U8: ec.Emit (OpCodes.Conv_U8); break;
  1716. case Mode.R4_CH: ec.Emit (OpCodes.Conv_U2); break;
  1717. case Mode.R8_I1: ec.Emit (OpCodes.Conv_I1); break;
  1718. case Mode.R8_U1: ec.Emit (OpCodes.Conv_U1); break;
  1719. case Mode.R8_I2: ec.Emit (OpCodes.Conv_I2); break;
  1720. case Mode.R8_U2: ec.Emit (OpCodes.Conv_U2); break;
  1721. case Mode.R8_I4: ec.Emit (OpCodes.Conv_I4); break;
  1722. case Mode.R8_U4: ec.Emit (OpCodes.Conv_U4); break;
  1723. case Mode.R8_I8: ec.Emit (OpCodes.Conv_I8); break;
  1724. case Mode.R8_U8: ec.Emit (OpCodes.Conv_U8); break;
  1725. case Mode.R8_CH: ec.Emit (OpCodes.Conv_U2); break;
  1726. case Mode.R8_R4: ec.Emit (OpCodes.Conv_R4); break;
  1727. case Mode.I_I8: ec.Emit (OpCodes.Conv_U8); break;
  1728. }
  1729. }
  1730. }
  1731. }
  1732. class OpcodeCast : TypeCast
  1733. {
  1734. readonly OpCode op;
  1735. public OpcodeCast (Expression child, TypeSpec return_type, OpCode op)
  1736. : base (child, return_type)
  1737. {
  1738. this.op = op;
  1739. }
  1740. protected override Expression DoResolve (ResolveContext ec)
  1741. {
  1742. // This should never be invoked, we are born in fully
  1743. // initialized state.
  1744. return this;
  1745. }
  1746. public override void Emit (EmitContext ec)
  1747. {
  1748. base.Emit (ec);
  1749. ec.Emit (op);
  1750. }
  1751. public TypeSpec UnderlyingType {
  1752. get { return child.Type; }
  1753. }
  1754. }
  1755. //
  1756. // Opcode casts expression with 2 opcodes but only
  1757. // single expression tree node
  1758. //
  1759. class OpcodeCastDuplex : OpcodeCast
  1760. {
  1761. readonly OpCode second;
  1762. public OpcodeCastDuplex (Expression child, TypeSpec returnType, OpCode first, OpCode second)
  1763. : base (child, returnType, first)
  1764. {
  1765. this.second = second;
  1766. }
  1767. public override void Emit (EmitContext ec)
  1768. {
  1769. base.Emit (ec);
  1770. ec.Emit (second);
  1771. }
  1772. }
  1773. /// <summary>
  1774. /// This kind of cast is used to encapsulate a child and cast it
  1775. /// to the class requested
  1776. /// </summary>
  1777. public sealed class ClassCast : TypeCast {
  1778. readonly bool forced;
  1779. public ClassCast (Expression child, TypeSpec return_type)
  1780. : base (child, return_type)
  1781. {
  1782. }
  1783. public ClassCast (Expression child, TypeSpec return_type, bool forced)
  1784. : base (child, return_type)
  1785. {
  1786. this.forced = forced;
  1787. }
  1788. public override void Emit (EmitContext ec)
  1789. {
  1790. base.Emit (ec);
  1791. bool gen = TypeManager.IsGenericParameter (child.Type);
  1792. if (gen)
  1793. ec.Emit (OpCodes.Box, child.Type);
  1794. if (type.IsGenericParameter) {
  1795. ec.Emit (OpCodes.Unbox_Any, type);
  1796. return;
  1797. }
  1798. if (gen && !forced)
  1799. return;
  1800. ec.Emit (OpCodes.Castclass, type);
  1801. }
  1802. }
  1803. //
  1804. // Created during resolving pahse when an expression is wrapped or constantified
  1805. // and original expression can be used later (e.g. for expression trees)
  1806. //
  1807. public class ReducedExpression : Expression
  1808. {
  1809. public sealed class ReducedConstantExpression : EmptyConstantCast
  1810. {
  1811. readonly Expression orig_expr;
  1812. public ReducedConstantExpression (Constant expr, Expression orig_expr)
  1813. : base (expr, expr.Type)
  1814. {
  1815. this.orig_expr = orig_expr;
  1816. }
  1817. public Expression OriginalExpression {
  1818. get {
  1819. return orig_expr;
  1820. }
  1821. }
  1822. public override Constant ConvertImplicitly (TypeSpec target_type)
  1823. {
  1824. Constant c = base.ConvertImplicitly (target_type);
  1825. if (c != null)
  1826. c = new ReducedConstantExpression (c, orig_expr);
  1827. return c;
  1828. }
  1829. public override Expression CreateExpressionTree (ResolveContext ec)
  1830. {
  1831. return orig_expr.CreateExpressionTree (ec);
  1832. }
  1833. public override Constant ConvertExplicitly (bool in_checked_context, TypeSpec target_type)
  1834. {
  1835. Constant c = base.ConvertExplicitly (in_checked_context, target_type);
  1836. if (c != null)
  1837. c = new ReducedConstantExpression (c, orig_expr);
  1838. return c;
  1839. }
  1840. public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType, TypeSpec parameterType)
  1841. {
  1842. //
  1843. // LAMESPEC: Reduced conditional expression is allowed as an attribute argument
  1844. //
  1845. if (orig_expr is Conditional)
  1846. child.EncodeAttributeValue (rc, enc, targetType,parameterType);
  1847. else
  1848. base.EncodeAttributeValue (rc, enc, targetType, parameterType);
  1849. }
  1850. }
  1851. sealed class ReducedExpressionStatement : ExpressionStatement
  1852. {
  1853. readonly Expression orig_expr;
  1854. readonly ExpressionStatement stm;
  1855. public ReducedExpressionStatement (ExpressionStatement stm, Expression orig)
  1856. {
  1857. this.orig_expr = orig;
  1858. this.stm = stm;
  1859. this.eclass = stm.eclass;
  1860. this.type = stm.Type;
  1861. this.loc = orig.Location;
  1862. }
  1863. public override bool ContainsEmitWithAwait ()
  1864. {
  1865. return stm.ContainsEmitWithAwait ();
  1866. }
  1867. public override Expression CreateExpressionTree (ResolveContext ec)
  1868. {
  1869. return orig_expr.CreateExpressionTree (ec);
  1870. }
  1871. protected override Expression DoResolve (ResolveContext ec)
  1872. {
  1873. return this;
  1874. }
  1875. public override void Emit (EmitContext ec)
  1876. {
  1877. stm.Emit (ec);
  1878. }
  1879. public override void EmitStatement (EmitContext ec)
  1880. {
  1881. stm.EmitStatement (ec);
  1882. }
  1883. public override void FlowAnalysis (FlowAnalysisContext fc)
  1884. {
  1885. stm.FlowAnalysis (fc);
  1886. }
  1887. }
  1888. readonly Expression expr, orig_expr;
  1889. private ReducedExpression (Expression expr, Expression orig_expr)
  1890. {
  1891. this.expr = expr;
  1892. this.eclass = expr.eclass;
  1893. this.type = expr.Type;
  1894. this.orig_expr = orig_expr;
  1895. this.loc = orig_expr.Location;
  1896. }
  1897. #region Properties
  1898. public override bool IsSideEffectFree {
  1899. get {
  1900. return expr.IsSideEffectFree;
  1901. }
  1902. }
  1903. public Expression OriginalExpression {
  1904. get {
  1905. return orig_expr;
  1906. }
  1907. }
  1908. #endregion
  1909. public override bool ContainsEmitWithAwait ()
  1910. {
  1911. return expr.ContainsEmitWithAwait ();
  1912. }
  1913. //
  1914. // Creates fully resolved expression switcher
  1915. //
  1916. public static Constant Create (Constant expr, Expression original_expr)
  1917. {
  1918. if (expr.eclass == ExprClass.Unresolved)
  1919. throw new ArgumentException ("Unresolved expression");
  1920. return new ReducedConstantExpression (expr, original_expr);
  1921. }
  1922. public static ExpressionStatement Create (ExpressionStatement s, Expression orig)
  1923. {
  1924. return new ReducedExpressionStatement (s, orig);
  1925. }
  1926. public static Expression Create (Expression expr, Expression original_expr)
  1927. {
  1928. return Create (expr, original_expr, true);
  1929. }
  1930. //
  1931. // Creates unresolved reduce expression. The original expression has to be
  1932. // already resolved. Created expression is constant based based on `expr'
  1933. // value unless canBeConstant is used
  1934. //
  1935. public static Expression Create (Expression expr, Expression original_expr, bool canBeConstant)
  1936. {
  1937. if (canBeConstant) {
  1938. Constant c = expr as Constant;
  1939. if (c != null)
  1940. return Create (c, original_expr);
  1941. }
  1942. ExpressionStatement s = expr as ExpressionStatement;
  1943. if (s != null)
  1944. return Create (s, original_expr);
  1945. if (expr.eclass == ExprClass.Unresolved)
  1946. throw new ArgumentException ("Unresolved expression");
  1947. return new ReducedExpression (expr, original_expr);
  1948. }
  1949. public override Expression CreateExpressionTree (ResolveContext ec)
  1950. {
  1951. return orig_expr.CreateExpressionTree (ec);
  1952. }
  1953. protected override Expression DoResolve (ResolveContext ec)
  1954. {
  1955. return this;
  1956. }
  1957. public override void Emit (EmitContext ec)
  1958. {
  1959. expr.Emit (ec);
  1960. }
  1961. public override Expression EmitToField (EmitContext ec)
  1962. {
  1963. return expr.EmitToField(ec);
  1964. }
  1965. public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
  1966. {
  1967. expr.EmitBranchable (ec, target, on_true);
  1968. }
  1969. public override void FlowAnalysis (FlowAnalysisContext fc)
  1970. {
  1971. expr.FlowAnalysis (fc);
  1972. }
  1973. public override SLE.Expression MakeExpression (BuilderContext ctx)
  1974. {
  1975. return orig_expr.MakeExpression (ctx);
  1976. }
  1977. }
  1978. //
  1979. // Standard composite pattern
  1980. //
  1981. public abstract class CompositeExpression : Expression
  1982. {
  1983. protected Expression expr;
  1984. protected CompositeExpression (Expression expr)
  1985. {
  1986. this.expr = expr;
  1987. this.loc = expr.Location;
  1988. }
  1989. public override bool ContainsEmitWithAwait ()
  1990. {
  1991. return expr.ContainsEmitWithAwait ();
  1992. }
  1993. public override Expression CreateExpressionTree (ResolveContext rc)
  1994. {
  1995. return expr.CreateExpressionTree (rc);
  1996. }
  1997. public Expression Child {
  1998. get { return expr; }
  1999. }
  2000. protected override Expression DoResolve (ResolveContext rc)
  2001. {
  2002. expr = expr.Resolve (rc);
  2003. if (expr == null)
  2004. return null;
  2005. type = expr.Type;
  2006. eclass = expr.eclass;
  2007. return this;
  2008. }
  2009. public override void Emit (EmitContext ec)
  2010. {
  2011. expr.Emit (ec);
  2012. }
  2013. public override bool IsNull {
  2014. get { return expr.IsNull; }
  2015. }
  2016. }
  2017. //
  2018. // Base of expressions used only to narrow resolve flow
  2019. //
  2020. public abstract class ShimExpression : Expression
  2021. {
  2022. protected Expression expr;
  2023. protected ShimExpression (Expression expr)
  2024. {
  2025. this.expr = expr;
  2026. }
  2027. public Expression Expr {
  2028. get {
  2029. return expr;
  2030. }
  2031. }
  2032. protected override void CloneTo (CloneContext clonectx, Expression t)
  2033. {
  2034. if (expr == null)
  2035. return;
  2036. ShimExpression target = (ShimExpression) t;
  2037. target.expr = expr.Clone (clonectx);
  2038. }
  2039. public override bool ContainsEmitWithAwait ()
  2040. {
  2041. return expr.ContainsEmitWithAwait ();
  2042. }
  2043. public override Expression CreateExpressionTree (ResolveContext ec)
  2044. {
  2045. throw new NotSupportedException ("ET");
  2046. }
  2047. public override void Emit (EmitContext ec)
  2048. {
  2049. throw new InternalErrorException ("Missing Resolve call");
  2050. }
  2051. }
  2052. public class UnreachableExpression : Expression
  2053. {
  2054. public UnreachableExpression (Expression expr)
  2055. {
  2056. this.loc = expr.Location;
  2057. }
  2058. public override Expression CreateExpressionTree (ResolveContext ec)
  2059. {
  2060. // TODO: is it ok
  2061. throw new NotImplementedException ();
  2062. }
  2063. protected override Expression DoResolve (ResolveContext rc)
  2064. {
  2065. throw new NotSupportedException ();
  2066. }
  2067. public override void FlowAnalysis (FlowAnalysisContext fc)
  2068. {
  2069. fc.Report.Warning (429, 4, loc, "Unreachable expression code detected");
  2070. }
  2071. public override void Emit (EmitContext ec)
  2072. {
  2073. }
  2074. public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
  2075. {
  2076. }
  2077. }
  2078. //
  2079. // Unresolved type name expressions
  2080. //
  2081. public abstract class ATypeNameExpression : FullNamedExpression
  2082. {
  2083. string name;
  2084. protected TypeArguments targs;
  2085. protected ATypeNameExpression (string name, Location l)
  2086. {
  2087. this.name = name;
  2088. loc = l;
  2089. }
  2090. protected ATypeNameExpression (string name, TypeArguments targs, Location l)
  2091. {
  2092. this.name = name;
  2093. this.targs = targs;
  2094. loc = l;
  2095. }
  2096. protected ATypeNameExpression (string name, int arity, Location l)
  2097. : this (name, new UnboundTypeArguments (arity), l)
  2098. {
  2099. }
  2100. #region Properties
  2101. protected int Arity {
  2102. get {
  2103. return targs == null ? 0 : targs.Count;
  2104. }
  2105. }
  2106. public bool HasTypeArguments {
  2107. get {
  2108. return targs != null && !targs.IsEmpty;
  2109. }
  2110. }
  2111. public string Name {
  2112. get {
  2113. return name;
  2114. }
  2115. set {
  2116. name = value;
  2117. }
  2118. }
  2119. public TypeArguments TypeArguments {
  2120. get {
  2121. return targs;
  2122. }
  2123. }
  2124. #endregion
  2125. public override bool Equals (object obj)
  2126. {
  2127. ATypeNameExpression atne = obj as ATypeNameExpression;
  2128. return atne != null && atne.Name == Name &&
  2129. (targs == null || targs.Equals (atne.targs));
  2130. }
  2131. protected void Error_OpenGenericTypeIsNotAllowed (IMemberContext mc)
  2132. {
  2133. mc.Module.Compiler.Report.Error (7003, Location, "Unbound generic name is not valid in this context");
  2134. }
  2135. public override int GetHashCode ()
  2136. {
  2137. return Name.GetHashCode ();
  2138. }
  2139. // TODO: Move it to MemberCore
  2140. public static string GetMemberType (MemberCore mc)
  2141. {
  2142. if (mc is Property)
  2143. return "property";
  2144. if (mc is Indexer)
  2145. return "indexer";
  2146. if (mc is FieldBase)
  2147. return "field";
  2148. if (mc is MethodCore)
  2149. return "method";
  2150. if (mc is EnumMember)
  2151. return "enum";
  2152. if (mc is Event)
  2153. return "event";
  2154. return "type";
  2155. }
  2156. public override string GetSignatureForError ()
  2157. {
  2158. if (targs != null) {
  2159. return Name + "<" + targs.GetSignatureForError () + ">";
  2160. }
  2161. return Name;
  2162. }
  2163. public abstract Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restriction);
  2164. }
  2165. /// <summary>
  2166. /// SimpleName expressions are formed of a single word and only happen at the beginning
  2167. /// of a dotted-name.
  2168. /// </summary>
  2169. public class SimpleName : ATypeNameExpression
  2170. {
  2171. public SimpleName (string name, Location l)
  2172. : base (name, l)
  2173. {
  2174. }
  2175. public SimpleName (string name, TypeArguments args, Location l)
  2176. : base (name, args, l)
  2177. {
  2178. }
  2179. public SimpleName (string name, int arity, Location l)
  2180. : base (name, arity, l)
  2181. {
  2182. }
  2183. public SimpleName GetMethodGroup ()
  2184. {
  2185. return new SimpleName (Name, targs, loc);
  2186. }
  2187. protected override Expression DoResolve (ResolveContext rc)
  2188. {
  2189. return SimpleNameResolve (rc, null);
  2190. }
  2191. public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
  2192. {
  2193. return SimpleNameResolve (ec, right_side);
  2194. }
  2195. public void Error_NameDoesNotExist (ResolveContext rc)
  2196. {
  2197. rc.Report.Error (103, loc, "The name `{0}' does not exist in the current context", Name);
  2198. }
  2199. protected virtual void Error_TypeOrNamespaceNotFound (IMemberContext ctx)
  2200. {
  2201. if (ctx.CurrentType != null) {
  2202. var member = MemberLookup (ctx, false, ctx.CurrentType, Name, 0, MemberLookupRestrictions.ExactArity, loc) as MemberExpr;
  2203. if (member != null) {
  2204. Error_UnexpectedKind (ctx, member, "type", member.KindName, loc);
  2205. return;
  2206. }
  2207. }
  2208. var report = ctx.Module.Compiler.Report;
  2209. var retval = ctx.LookupNamespaceOrType (Name, Arity, LookupMode.IgnoreAccessibility, loc);
  2210. if (retval != null) {
  2211. report.SymbolRelatedToPreviousError (retval.Type);
  2212. ErrorIsInaccesible (ctx, retval.GetSignatureForError (), loc);
  2213. return;
  2214. }
  2215. retval = ctx.LookupNamespaceOrType (Name, -System.Math.Max (1, Arity), LookupMode.Probing, loc);
  2216. if (retval != null) {
  2217. Error_TypeArgumentsCannotBeUsed (ctx, retval.Type, loc);
  2218. return;
  2219. }
  2220. var ns_candidates = ctx.Module.GlobalRootNamespace.FindTypeNamespaces (ctx, Name, Arity);
  2221. if (ns_candidates != null) {
  2222. if (ctx is UsingAliasNamespace.AliasContext) {
  2223. report.Error (246, loc,
  2224. "The type or namespace name `{1}' could not be found. Consider using fully qualified name `{0}.{1}'",
  2225. ns_candidates[0], Name);
  2226. } else {
  2227. string usings = string.Join ("' or `", ns_candidates.ToArray ());
  2228. report.Error (246, loc,
  2229. "The type or namespace name `{0}' could not be found. Are you missing `{1}' using directive?",
  2230. Name, usings);
  2231. }
  2232. } else {
  2233. report.Error (246, loc,
  2234. "The type or namespace name `{0}' could not be found. Are you missing an assembly reference?",
  2235. Name);
  2236. }
  2237. }
  2238. public override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc, bool allowUnboundTypeArguments)
  2239. {
  2240. FullNamedExpression fne = mc.LookupNamespaceOrType (Name, Arity, LookupMode.Normal, loc);
  2241. if (fne != null) {
  2242. if (fne.Type != null && Arity > 0) {
  2243. if (HasTypeArguments) {
  2244. GenericTypeExpr ct = new GenericTypeExpr (fne.Type, targs, loc);
  2245. if (ct.ResolveAsType (mc) == null)
  2246. return null;
  2247. return ct;
  2248. }
  2249. if (!allowUnboundTypeArguments)
  2250. Error_OpenGenericTypeIsNotAllowed (mc);
  2251. return new GenericOpenTypeExpr (fne.Type, loc);
  2252. }
  2253. //
  2254. // dynamic namespace is ignored when dynamic is allowed (does not apply to types)
  2255. //
  2256. if (!(fne is NamespaceExpression))
  2257. return fne;
  2258. }
  2259. if (Arity == 0 && Name == "dynamic" && mc.Module.Compiler.Settings.Version > LanguageVersion.V_3) {
  2260. if (!mc.Module.PredefinedAttributes.Dynamic.IsDefined) {
  2261. mc.Module.Compiler.Report.Error (1980, Location,
  2262. "Dynamic keyword requires `{0}' to be defined. Are you missing System.Core.dll assembly reference?",
  2263. mc.Module.PredefinedAttributes.Dynamic.GetSignatureForError ());
  2264. }
  2265. fne = new DynamicTypeExpr (loc);
  2266. fne.ResolveAsType (mc);
  2267. }
  2268. if (fne != null)
  2269. return fne;
  2270. Error_TypeOrNamespaceNotFound (mc);
  2271. return null;
  2272. }
  2273. public bool IsPossibleTypeOrNamespace (IMemberContext mc)
  2274. {
  2275. return mc.LookupNamespaceOrType (Name, Arity, LookupMode.Probing, loc) != null;
  2276. }
  2277. public override Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restrictions)
  2278. {
  2279. int lookup_arity = Arity;
  2280. bool errorMode = false;
  2281. Expression e;
  2282. Block current_block = rc.CurrentBlock;
  2283. INamedBlockVariable variable = null;
  2284. bool variable_found = false;
  2285. while (true) {
  2286. //
  2287. // Stage 1: binding to local variables or parameters
  2288. //
  2289. // LAMESPEC: It should take invocableOnly into account but that would break csc compatibility
  2290. //
  2291. if (current_block != null && lookup_arity == 0) {
  2292. if (current_block.ParametersBlock.TopBlock.GetLocalName (Name, current_block.Original, ref variable)) {
  2293. if (!variable.IsDeclared) {
  2294. // We found local name in accessible block but it's not
  2295. // initialized yet, maybe the user wanted to bind to something else
  2296. errorMode = true;
  2297. variable_found = true;
  2298. } else {
  2299. e = variable.CreateReferenceExpression (rc, loc);
  2300. if (e != null) {
  2301. if (Arity > 0)
  2302. Error_TypeArgumentsCannotBeUsed (rc, "variable", Name, loc);
  2303. return e;
  2304. }
  2305. }
  2306. }
  2307. }
  2308. //
  2309. // Stage 2: Lookup members if we are inside a type up to top level type for nested types
  2310. //
  2311. TypeSpec member_type = rc.CurrentType;
  2312. for (; member_type != null; member_type = member_type.DeclaringType) {
  2313. e = MemberLookup (rc, errorMode, member_type, Name, lookup_arity, restrictions, loc);
  2314. if (e == null)
  2315. continue;
  2316. var me = e as MemberExpr;
  2317. if (me == null) {
  2318. // The name matches a type, defer to ResolveAsTypeStep
  2319. if (e is TypeExpr)
  2320. break;
  2321. continue;
  2322. }
  2323. if (errorMode) {
  2324. if (variable != null) {
  2325. if (me is FieldExpr || me is ConstantExpr || me is EventExpr || me is PropertyExpr) {
  2326. rc.Report.Error (844, loc,
  2327. "A local variable `{0}' cannot be used before it is declared. Consider renaming the local variable when it hides the member `{1}'",
  2328. Name, me.GetSignatureForError ());
  2329. } else {
  2330. break;
  2331. }
  2332. } else if (me is MethodGroupExpr || me is PropertyExpr || me is IndexerExpr) {
  2333. // Leave it to overload resolution to report correct error
  2334. } else {
  2335. // TODO: rc.Report.SymbolRelatedToPreviousError ()
  2336. ErrorIsInaccesible (rc, me.GetSignatureForError (), loc);
  2337. }
  2338. } else {
  2339. // LAMESPEC: again, ignores InvocableOnly
  2340. if (variable != null) {
  2341. rc.Report.SymbolRelatedToPreviousError (variable.Location, Name);
  2342. rc.Report.Error (135, loc, "`{0}' conflicts with a declaration in a child block", Name);
  2343. }
  2344. //
  2345. // MemberLookup does not check accessors availability, this is actually needed for properties only
  2346. //
  2347. var pe = me as PropertyExpr;
  2348. if (pe != null) {
  2349. // Break as there is no other overload available anyway
  2350. if ((restrictions & MemberLookupRestrictions.ReadAccess) != 0) {
  2351. if (!pe.PropertyInfo.HasGet || !pe.PropertyInfo.Get.IsAccessible (rc))
  2352. break;
  2353. pe.Getter = pe.PropertyInfo.Get;
  2354. } else {
  2355. if (!pe.PropertyInfo.HasSet || !pe.PropertyInfo.Set.IsAccessible (rc))
  2356. break;
  2357. pe.Setter = pe.PropertyInfo.Set;
  2358. }
  2359. }
  2360. }
  2361. // TODO: It's used by EventExpr -> FieldExpr transformation only
  2362. // TODO: Should go to MemberAccess
  2363. me = me.ResolveMemberAccess (rc, null, null);
  2364. if (Arity > 0) {
  2365. targs.Resolve (rc);
  2366. me.SetTypeArguments (rc, targs);
  2367. }
  2368. return me;
  2369. }
  2370. //
  2371. // Stage 3: Lookup nested types, namespaces and type parameters in the context
  2372. //
  2373. if ((restrictions & MemberLookupRestrictions.InvocableOnly) == 0 && !variable_found) {
  2374. if (IsPossibleTypeOrNamespace (rc)) {
  2375. if (variable != null) {
  2376. rc.Report.SymbolRelatedToPreviousError (variable.Location, Name);
  2377. rc.Report.Error (135, loc, "`{0}' conflicts with a declaration in a child block", Name);
  2378. }
  2379. return ResolveAsTypeOrNamespace (rc, false);
  2380. }
  2381. }
  2382. var mg = NamespaceContainer.LookupStaticUsings (rc, Name, Arity, loc);
  2383. if (mg != null) {
  2384. if (Arity > 0) {
  2385. targs.Resolve (rc);
  2386. mg.SetTypeArguments (rc, targs);
  2387. }
  2388. return mg;
  2389. }
  2390. if (Name == "nameof")
  2391. return new NameOf (this);
  2392. if (errorMode) {
  2393. if (variable_found) {
  2394. rc.Report.Error (841, loc, "A local variable `{0}' cannot be used before it is declared", Name);
  2395. } else {
  2396. if (Arity > 0) {
  2397. var tparams = rc.CurrentTypeParameters;
  2398. if (tparams != null) {
  2399. if (tparams.Find (Name) != null) {
  2400. Error_TypeArgumentsCannotBeUsed (rc, "type parameter", Name, loc);
  2401. return null;
  2402. }
  2403. }
  2404. var ct = rc.CurrentType;
  2405. do {
  2406. if (ct.MemberDefinition.TypeParametersCount > 0) {
  2407. foreach (var ctp in ct.MemberDefinition.TypeParameters) {
  2408. if (ctp.Name == Name) {
  2409. Error_TypeArgumentsCannotBeUsed (rc, "type parameter", Name, loc);
  2410. return null;
  2411. }
  2412. }
  2413. }
  2414. ct = ct.DeclaringType;
  2415. } while (ct != null);
  2416. }
  2417. if ((restrictions & MemberLookupRestrictions.InvocableOnly) == 0) {
  2418. e = rc.LookupNamespaceOrType (Name, Arity, LookupMode.IgnoreAccessibility, loc);
  2419. if (e != null) {
  2420. rc.Report.SymbolRelatedToPreviousError (e.Type);
  2421. ErrorIsInaccesible (rc, e.GetSignatureForError (), loc);
  2422. return e;
  2423. }
  2424. } else {
  2425. var me = MemberLookup (rc, false, rc.CurrentType, Name, Arity, restrictions & ~MemberLookupRestrictions.InvocableOnly, loc) as MemberExpr;
  2426. if (me != null) {
  2427. Error_UnexpectedKind (rc, me, "method group", me.KindName, loc);
  2428. return ErrorExpression.Instance;
  2429. }
  2430. }
  2431. e = rc.LookupNamespaceOrType (Name, -System.Math.Max (1, Arity), LookupMode.Probing, loc);
  2432. if (e != null) {
  2433. if (e.Type.Arity != Arity && (restrictions & MemberLookupRestrictions.IgnoreArity) == 0) {
  2434. Error_TypeArgumentsCannotBeUsed (rc, e.Type, loc);
  2435. return e;
  2436. }
  2437. if (e is TypeExpr) {
  2438. // TypeExpression does not have correct location
  2439. if (e is TypeExpression)
  2440. e = new TypeExpression (e.Type, loc);
  2441. return e;
  2442. }
  2443. }
  2444. Error_NameDoesNotExist (rc);
  2445. }
  2446. return ErrorExpression.Instance;
  2447. }
  2448. if (rc.Module.Evaluator != null) {
  2449. var fi = rc.Module.Evaluator.LookupField (Name);
  2450. if (fi != null)
  2451. return new FieldExpr (fi.Item1, loc);
  2452. }
  2453. lookup_arity = 0;
  2454. errorMode = true;
  2455. }
  2456. }
  2457. Expression SimpleNameResolve (ResolveContext ec, Expression right_side)
  2458. {
  2459. Expression e = LookupNameExpression (ec, right_side == null ? MemberLookupRestrictions.ReadAccess : MemberLookupRestrictions.None);
  2460. if (e == null)
  2461. return null;
  2462. if (e is FullNamedExpression && e.eclass != ExprClass.Unresolved) {
  2463. Error_UnexpectedKind (ec, e, "variable", e.ExprClassName, loc);
  2464. return e;
  2465. }
  2466. if (right_side != null) {
  2467. e = e.ResolveLValue (ec, right_side);
  2468. } else {
  2469. e = e.Resolve (ec);
  2470. }
  2471. return e;
  2472. }
  2473. public override object Accept (StructuralVisitor visitor)
  2474. {
  2475. return visitor.Visit (this);
  2476. }
  2477. }
  2478. /// <summary>
  2479. /// Represents a namespace or a type. The name of the class was inspired by
  2480. /// section 10.8.1 (Fully Qualified Names).
  2481. /// </summary>
  2482. public abstract class FullNamedExpression : Expression
  2483. {
  2484. protected override void CloneTo (CloneContext clonectx, Expression target)
  2485. {
  2486. // Do nothing, most unresolved type expressions cannot be
  2487. // resolved to different type
  2488. }
  2489. public override bool ContainsEmitWithAwait ()
  2490. {
  2491. return false;
  2492. }
  2493. public override Expression CreateExpressionTree (ResolveContext ec)
  2494. {
  2495. throw new NotSupportedException ("ET");
  2496. }
  2497. public abstract FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc, bool allowUnboundTypeArguments);
  2498. //
  2499. // This is used to resolve the expression as a type, a null
  2500. // value will be returned if the expression is not a type
  2501. // reference
  2502. //
  2503. public override TypeSpec ResolveAsType (IMemberContext mc, bool allowUnboundTypeArguments = false)
  2504. {
  2505. FullNamedExpression fne = ResolveAsTypeOrNamespace (mc, allowUnboundTypeArguments);
  2506. if (fne == null)
  2507. return null;
  2508. TypeExpr te = fne as TypeExpr;
  2509. if (te == null) {
  2510. Error_UnexpectedKind (mc, fne, "type", fne.ExprClassName, loc);
  2511. return null;
  2512. }
  2513. te.loc = loc;
  2514. type = te.Type;
  2515. var dep = type.GetMissingDependencies ();
  2516. if (dep != null) {
  2517. ImportedTypeDefinition.Error_MissingDependency (mc, dep, loc);
  2518. }
  2519. if (type.Kind == MemberKind.Void) {
  2520. mc.Module.Compiler.Report.Error (673, loc, "System.Void cannot be used from C#. Consider using `void'");
  2521. }
  2522. //
  2523. // Obsolete checks cannot be done when resolving base context as they
  2524. // require type dependencies to be set but we are in process of resolving them
  2525. //
  2526. if (!(mc is TypeDefinition.BaseContext) && !(mc is UsingAliasNamespace.AliasContext)) {
  2527. ObsoleteAttribute obsolete_attr = type.GetAttributeObsolete ();
  2528. if (obsolete_attr != null && !mc.IsObsolete) {
  2529. AttributeTester.Report_ObsoleteMessage (obsolete_attr, te.GetSignatureForError (), Location, mc.Module.Compiler.Report);
  2530. }
  2531. }
  2532. return type;
  2533. }
  2534. public override void Emit (EmitContext ec)
  2535. {
  2536. throw new InternalErrorException ("FullNamedExpression `{0}' found in resolved tree",
  2537. GetSignatureForError ());
  2538. }
  2539. }
  2540. /// <summary>
  2541. /// Expression that evaluates to a type
  2542. /// </summary>
  2543. public abstract class TypeExpr : FullNamedExpression
  2544. {
  2545. public sealed override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc, bool allowUnboundTypeArguments)
  2546. {
  2547. ResolveAsType (mc);
  2548. return this;
  2549. }
  2550. protected sealed override Expression DoResolve (ResolveContext ec)
  2551. {
  2552. ResolveAsType (ec);
  2553. return this;
  2554. }
  2555. public override bool Equals (object obj)
  2556. {
  2557. TypeExpr tobj = obj as TypeExpr;
  2558. if (tobj == null)
  2559. return false;
  2560. return Type == tobj.Type;
  2561. }
  2562. public override int GetHashCode ()
  2563. {
  2564. return Type.GetHashCode ();
  2565. }
  2566. }
  2567. /// <summary>
  2568. /// Fully resolved Expression that already evaluated to a type
  2569. /// </summary>
  2570. public class TypeExpression : TypeExpr
  2571. {
  2572. public TypeExpression (TypeSpec t, Location l)
  2573. {
  2574. Type = t;
  2575. eclass = ExprClass.Type;
  2576. loc = l;
  2577. }
  2578. public sealed override TypeSpec ResolveAsType (IMemberContext mc, bool allowUnboundTypeArguments = false)
  2579. {
  2580. return type;
  2581. }
  2582. public override object Accept (StructuralVisitor visitor)
  2583. {
  2584. return visitor.Visit (this);
  2585. }
  2586. }
  2587. public class NamespaceExpression : FullNamedExpression
  2588. {
  2589. readonly Namespace ns;
  2590. public NamespaceExpression (Namespace ns, Location loc)
  2591. {
  2592. this.ns = ns;
  2593. this.Type = InternalType.Namespace;
  2594. this.eclass = ExprClass.Namespace;
  2595. this.loc = loc;
  2596. }
  2597. public Namespace Namespace {
  2598. get {
  2599. return ns;
  2600. }
  2601. }
  2602. protected override Expression DoResolve (ResolveContext rc)
  2603. {
  2604. throw new NotImplementedException ();
  2605. }
  2606. public override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc, bool allowUnboundTypeArguments)
  2607. {
  2608. return this;
  2609. }
  2610. public void Error_NamespaceDoesNotExist (IMemberContext ctx, string name, int arity)
  2611. {
  2612. var retval = Namespace.LookupType (ctx, name, arity, LookupMode.IgnoreAccessibility, loc);
  2613. if (retval != null) {
  2614. // ctx.Module.Compiler.Report.SymbolRelatedToPreviousError (retval.MemberDefinition);
  2615. ErrorIsInaccesible (ctx, retval.GetSignatureForError (), loc);
  2616. return;
  2617. }
  2618. retval = Namespace.LookupType (ctx, name, -System.Math.Max (1, arity), LookupMode.Probing, loc);
  2619. if (retval != null) {
  2620. Error_TypeArgumentsCannotBeUsed (ctx, retval, loc);
  2621. return;
  2622. }
  2623. Namespace ns;
  2624. if (arity > 0 && Namespace.TryGetNamespace (name, out ns)) {
  2625. Error_TypeArgumentsCannotBeUsed (ctx, ExprClassName, ns.GetSignatureForError (), loc);
  2626. return;
  2627. }
  2628. string assembly = null;
  2629. string possible_name = Namespace.GetSignatureForError () + "." + name;
  2630. // Only assembly unique name should be added
  2631. switch (possible_name) {
  2632. case "System.Drawing":
  2633. case "System.Web.Services":
  2634. case "System.Web":
  2635. case "System.Data":
  2636. case "System.Configuration":
  2637. case "System.Data.Services":
  2638. case "System.DirectoryServices":
  2639. case "System.Json":
  2640. case "System.Net.Http":
  2641. case "System.Numerics":
  2642. case "System.Runtime.Caching":
  2643. case "System.ServiceModel":
  2644. case "System.Transactions":
  2645. case "System.Web.Routing":
  2646. case "System.Xml.Linq":
  2647. case "System.Xml":
  2648. assembly = possible_name;
  2649. break;
  2650. case "System.Linq":
  2651. case "System.Linq.Expressions":
  2652. assembly = "System.Core";
  2653. break;
  2654. case "System.Windows.Forms":
  2655. case "System.Windows.Forms.Layout":
  2656. assembly = "System.Windows.Forms";
  2657. break;
  2658. }
  2659. assembly = assembly == null ? "an" : "`" + assembly + "'";
  2660. if (Namespace is GlobalRootNamespace) {
  2661. ctx.Module.Compiler.Report.Error (400, loc,
  2662. "The type or namespace name `{0}' could not be found in the global namespace. Are you missing {1} assembly reference?",
  2663. name, assembly);
  2664. } else {
  2665. ctx.Module.Compiler.Report.Error (234, loc,
  2666. "The type or namespace name `{0}' does not exist in the namespace `{1}'. Are you missing {2} assembly reference?",
  2667. name, GetSignatureForError (), assembly);
  2668. }
  2669. }
  2670. public override string GetSignatureForError ()
  2671. {
  2672. return ns.GetSignatureForError ();
  2673. }
  2674. public FullNamedExpression LookupTypeOrNamespace (IMemberContext ctx, string name, int arity, LookupMode mode, Location loc)
  2675. {
  2676. return ns.LookupTypeOrNamespace (ctx, name, arity, mode, loc);
  2677. }
  2678. }
  2679. /// <summary>
  2680. /// This class denotes an expression which evaluates to a member
  2681. /// of a struct or a class.
  2682. /// </summary>
  2683. public abstract class MemberExpr : Expression, OverloadResolver.IInstanceQualifier
  2684. {
  2685. protected bool conditional_access_receiver;
  2686. //
  2687. // An instance expression associated with this member, if it's a
  2688. // non-static member
  2689. //
  2690. public Expression InstanceExpression;
  2691. /// <summary>
  2692. /// The name of this member.
  2693. /// </summary>
  2694. public abstract string Name {
  2695. get;
  2696. }
  2697. //
  2698. // When base.member is used
  2699. //
  2700. public bool IsBase {
  2701. get { return InstanceExpression is BaseThis; }
  2702. }
  2703. /// <summary>
  2704. /// Whether this is an instance member.
  2705. /// </summary>
  2706. public abstract bool IsInstance {
  2707. get;
  2708. }
  2709. /// <summary>
  2710. /// Whether this is a static member.
  2711. /// </summary>
  2712. public abstract bool IsStatic {
  2713. get;
  2714. }
  2715. public abstract string KindName {
  2716. get;
  2717. }
  2718. public bool ConditionalAccess { get; set; }
  2719. protected abstract TypeSpec DeclaringType {
  2720. get;
  2721. }
  2722. TypeSpec OverloadResolver.IInstanceQualifier.InstanceType {
  2723. get {
  2724. return InstanceExpression.Type;
  2725. }
  2726. }
  2727. //
  2728. // Converts best base candidate for virtual method starting from QueriedBaseType
  2729. //
  2730. protected MethodSpec CandidateToBaseOverride (ResolveContext rc, MethodSpec method)
  2731. {
  2732. //
  2733. // Only when base.member is used and method is virtual
  2734. //
  2735. if (!IsBase)
  2736. return method;
  2737. //
  2738. // Overload resulution works on virtual or non-virtual members only (no overrides). That
  2739. // means for base.member access we have to find the closest match after we found best candidate
  2740. //
  2741. if ((method.Modifiers & (Modifiers.ABSTRACT | Modifiers.VIRTUAL | Modifiers.OVERRIDE)) != 0) {
  2742. //
  2743. // The method could already be what we are looking for
  2744. //
  2745. TypeSpec[] targs = null;
  2746. if (method.DeclaringType != InstanceExpression.Type) {
  2747. //
  2748. // Candidate can have inflated MVAR parameters and we need to find
  2749. // base match for original definition not inflated parameter types
  2750. //
  2751. var parameters = method.Parameters;
  2752. if (method.Arity > 0) {
  2753. parameters = ((IParametersMember) method.MemberDefinition).Parameters;
  2754. var inflated = method.DeclaringType as InflatedTypeSpec;
  2755. if (inflated != null) {
  2756. parameters = parameters.Inflate (inflated.CreateLocalInflator (rc));
  2757. }
  2758. }
  2759. var filter = new MemberFilter (method.Name, method.Arity, MemberKind.Method, parameters, null);
  2760. var base_override = MemberCache.FindMember (InstanceExpression.Type, filter, BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as MethodSpec;
  2761. if (base_override != null && base_override.DeclaringType != method.DeclaringType) {
  2762. if (base_override.IsGeneric)
  2763. targs = method.TypeArguments;
  2764. method = base_override;
  2765. }
  2766. }
  2767. //
  2768. // When base access is used inside anonymous method/iterator/etc we need to
  2769. // get back to the context of original type. We do it by emiting proxy
  2770. // method in original class and rewriting base call to this compiler
  2771. // generated method call which does the actual base invocation. This may
  2772. // introduce redundant storey but with `this' only but it's tricky to avoid
  2773. // at this stage as we don't know what expressions follow base
  2774. //
  2775. if (rc.CurrentAnonymousMethod != null) {
  2776. if (targs == null && method.IsGeneric) {
  2777. targs = method.TypeArguments;
  2778. method = method.GetGenericMethodDefinition ();
  2779. }
  2780. if (method.Parameters.HasArglist)
  2781. throw new NotImplementedException ("__arglist base call proxy");
  2782. method = rc.CurrentMemberDefinition.Parent.PartialContainer.CreateHoistedBaseCallProxy (rc, method);
  2783. // Ideally this should apply to any proxy rewrite but in the case of unary mutators on
  2784. // get/set member expressions second call would fail to proxy because left expression
  2785. // would be of 'this' and not 'base' because we share InstanceExpression for get/set
  2786. // FIXME: The async check is another hack but will probably fail with mutators
  2787. if (rc.CurrentType.IsStruct || rc.CurrentAnonymousMethod.Storey is AsyncTaskStorey)
  2788. InstanceExpression = new This (loc).Resolve (rc);
  2789. }
  2790. if (targs != null)
  2791. method = method.MakeGenericMethod (rc, targs);
  2792. }
  2793. //
  2794. // Only base will allow this invocation to happen.
  2795. //
  2796. if (method.IsAbstract) {
  2797. rc.Report.SymbolRelatedToPreviousError (method);
  2798. Error_CannotCallAbstractBase (rc, method.GetSignatureForError ());
  2799. }
  2800. return method;
  2801. }
  2802. protected void CheckProtectedMemberAccess (ResolveContext rc, MemberSpec member)
  2803. {
  2804. if (InstanceExpression == null)
  2805. return;
  2806. if ((member.Modifiers & Modifiers.PROTECTED) != 0 && !(InstanceExpression is This)) {
  2807. if (!CheckProtectedMemberAccess (rc, member, InstanceExpression.Type)) {
  2808. Error_ProtectedMemberAccess (rc, member, InstanceExpression.Type, loc);
  2809. }
  2810. }
  2811. }
  2812. bool OverloadResolver.IInstanceQualifier.CheckProtectedMemberAccess (ResolveContext rc, MemberSpec member)
  2813. {
  2814. if (InstanceExpression == null)
  2815. return true;
  2816. return InstanceExpression is This || CheckProtectedMemberAccess (rc, member, InstanceExpression.Type);
  2817. }
  2818. public static bool CheckProtectedMemberAccess<T> (ResolveContext rc, T member, TypeSpec qualifier) where T : MemberSpec
  2819. {
  2820. var ct = rc.CurrentType;
  2821. if (ct == qualifier)
  2822. return true;
  2823. if ((member.Modifiers & Modifiers.INTERNAL) != 0 && member.DeclaringType.MemberDefinition.IsInternalAsPublic (ct.MemberDefinition.DeclaringAssembly))
  2824. return true;
  2825. qualifier = qualifier.GetDefinition ();
  2826. if (ct != qualifier && !IsSameOrBaseQualifier (ct, qualifier)) {
  2827. return false;
  2828. }
  2829. return true;
  2830. }
  2831. public override bool ContainsEmitWithAwait ()
  2832. {
  2833. return InstanceExpression != null && InstanceExpression.ContainsEmitWithAwait ();
  2834. }
  2835. public override bool HasConditionalAccess ()
  2836. {
  2837. return ConditionalAccess || (InstanceExpression != null && InstanceExpression.HasConditionalAccess ());
  2838. }
  2839. static bool IsSameOrBaseQualifier (TypeSpec type, TypeSpec qtype)
  2840. {
  2841. do {
  2842. type = type.GetDefinition ();
  2843. if (type == qtype || TypeManager.IsFamilyAccessible (qtype, type))
  2844. return true;
  2845. type = type.DeclaringType;
  2846. } while (type != null);
  2847. return false;
  2848. }
  2849. protected void DoBestMemberChecks<T> (ResolveContext rc, T member) where T : MemberSpec, IInterfaceMemberSpec
  2850. {
  2851. if (InstanceExpression != null) {
  2852. InstanceExpression = InstanceExpression.Resolve (rc);
  2853. CheckProtectedMemberAccess (rc, member);
  2854. }
  2855. if (member.MemberType.IsPointer && !rc.IsUnsafe) {
  2856. UnsafeError (rc, loc);
  2857. }
  2858. var dep = member.GetMissingDependencies ();
  2859. if (dep != null) {
  2860. ImportedTypeDefinition.Error_MissingDependency (rc, dep, loc);
  2861. }
  2862. if (!rc.IsObsolete) {
  2863. ObsoleteAttribute oa = member.GetAttributeObsolete ();
  2864. if (oa != null)
  2865. AttributeTester.Report_ObsoleteMessage (oa, member.GetSignatureForError (), loc, rc.Report);
  2866. }
  2867. if (!(member is FieldSpec))
  2868. member.MemberDefinition.SetIsUsed ();
  2869. }
  2870. protected virtual void Error_CannotCallAbstractBase (ResolveContext rc, string name)
  2871. {
  2872. rc.Report.Error (205, loc, "Cannot call an abstract base member `{0}'", name);
  2873. }
  2874. public static void Error_ProtectedMemberAccess (ResolveContext rc, MemberSpec member, TypeSpec qualifier, Location loc)
  2875. {
  2876. rc.Report.SymbolRelatedToPreviousError (member);
  2877. rc.Report.Error (1540, loc,
  2878. "Cannot access protected member `{0}' via a qualifier of type `{1}'. The qualifier must be of type `{2}' or derived from it",
  2879. member.GetSignatureForError (), qualifier.GetSignatureForError (), rc.CurrentType.GetSignatureForError ());
  2880. }
  2881. public override void FlowAnalysis (FlowAnalysisContext fc)
  2882. {
  2883. if (InstanceExpression != null) {
  2884. InstanceExpression.FlowAnalysis (fc);
  2885. if (ConditionalAccess) {
  2886. fc.BranchConditionalAccessDefiniteAssignment ();
  2887. }
  2888. }
  2889. }
  2890. protected void ResolveConditionalAccessReceiver (ResolveContext rc)
  2891. {
  2892. if (!rc.HasSet (ResolveContext.Options.ConditionalAccessReceiver)) {
  2893. if (HasConditionalAccess ()) {
  2894. conditional_access_receiver = true;
  2895. rc.Set (ResolveContext.Options.ConditionalAccessReceiver);
  2896. }
  2897. }
  2898. }
  2899. public bool ResolveInstanceExpression (ResolveContext rc, Expression rhs)
  2900. {
  2901. if (!ResolveInstanceExpressionCore (rc, rhs))
  2902. return false;
  2903. //
  2904. // Check intermediate value modification which won't have any effect
  2905. //
  2906. if (rhs != null && TypeSpec.IsValueType (InstanceExpression.Type)) {
  2907. var fexpr = InstanceExpression as FieldExpr;
  2908. if (fexpr != null) {
  2909. if (!fexpr.Spec.IsReadOnly || rc.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.ConstructorScope))
  2910. return true;
  2911. if (fexpr.IsStatic) {
  2912. rc.Report.Error (1650, loc, "Fields of static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
  2913. fexpr.GetSignatureForError ());
  2914. } else {
  2915. rc.Report.Error (1648, loc, "Members of readonly field `{0}' cannot be modified (except in a constructor or a variable initializer)",
  2916. fexpr.GetSignatureForError ());
  2917. }
  2918. return true;
  2919. }
  2920. if (InstanceExpression is PropertyExpr || InstanceExpression is IndexerExpr || InstanceExpression is Invocation) {
  2921. if (rc.CurrentInitializerVariable != null) {
  2922. rc.Report.Error (1918, loc, "Members of value type `{0}' cannot be assigned using a property `{1}' object initializer",
  2923. InstanceExpression.Type.GetSignatureForError (), InstanceExpression.GetSignatureForError ());
  2924. } else {
  2925. rc.Report.Error (1612, loc,
  2926. "Cannot modify a value type return value of `{0}'. Consider storing the value in a temporary variable",
  2927. InstanceExpression.GetSignatureForError ());
  2928. }
  2929. return true;
  2930. }
  2931. var lvr = InstanceExpression as LocalVariableReference;
  2932. if (lvr != null) {
  2933. if (!lvr.local_info.IsReadonly)
  2934. return true;
  2935. rc.Report.Error (1654, loc, "Cannot assign to members of `{0}' because it is a `{1}'",
  2936. InstanceExpression.GetSignatureForError (), lvr.local_info.GetReadOnlyContext ());
  2937. }
  2938. }
  2939. return true;
  2940. }
  2941. bool ResolveInstanceExpressionCore (ResolveContext rc, Expression rhs)
  2942. {
  2943. if (IsStatic) {
  2944. if (InstanceExpression != null) {
  2945. if (InstanceExpression is TypeExpr) {
  2946. var t = InstanceExpression.Type;
  2947. do {
  2948. ObsoleteAttribute oa = t.GetAttributeObsolete ();
  2949. if (oa != null && !rc.IsObsolete) {
  2950. AttributeTester.Report_ObsoleteMessage (oa, t.GetSignatureForError (), loc, rc.Report);
  2951. }
  2952. t = t.DeclaringType;
  2953. } while (t != null);
  2954. } else {
  2955. var runtime_expr = InstanceExpression as RuntimeValueExpression;
  2956. if (runtime_expr == null || !runtime_expr.IsSuggestionOnly) {
  2957. rc.Report.Error (176, loc,
  2958. "Static member `{0}' cannot be accessed with an instance reference, qualify it with a type name instead",
  2959. GetSignatureForError ());
  2960. }
  2961. }
  2962. InstanceExpression = null;
  2963. }
  2964. return false;
  2965. }
  2966. if (InstanceExpression == null || InstanceExpression is TypeExpr) {
  2967. if (InstanceExpression != null || !This.IsThisAvailable (rc, true)) {
  2968. if (rc.HasSet (ResolveContext.Options.FieldInitializerScope)) {
  2969. rc.Report.Error (236, loc,
  2970. "A field initializer cannot reference the nonstatic field, method, or property `{0}'",
  2971. GetSignatureForError ());
  2972. } else {
  2973. var fe = this as FieldExpr;
  2974. if (fe != null && fe.Spec.MemberDefinition is PrimaryConstructorField) {
  2975. if (rc.HasSet (ResolveContext.Options.BaseInitializer)) {
  2976. rc.Report.Error (9005, loc, "Constructor initializer cannot access primary constructor parameters");
  2977. } else {
  2978. rc.Report.Error (9006, loc, "An object reference is required to access primary constructor parameter `{0}'",
  2979. fe.Name);
  2980. }
  2981. } else {
  2982. rc.Report.Error (120, loc,
  2983. "An object reference is required to access non-static member `{0}'",
  2984. GetSignatureForError ());
  2985. }
  2986. }
  2987. InstanceExpression = new CompilerGeneratedThis (rc.CurrentType, loc).Resolve (rc);
  2988. return false;
  2989. }
  2990. if (!TypeManager.IsFamilyAccessible (rc.CurrentType, DeclaringType)) {
  2991. rc.Report.Error (38, loc,
  2992. "Cannot access a nonstatic member of outer type `{0}' via nested type `{1}'",
  2993. DeclaringType.GetSignatureForError (), rc.CurrentType.GetSignatureForError ());
  2994. }
  2995. InstanceExpression = new This (loc).Resolve (rc);
  2996. return false;
  2997. }
  2998. var me = InstanceExpression as MemberExpr;
  2999. if (me != null) {
  3000. me.ResolveInstanceExpressionCore (rc, rhs);
  3001. var fe = me as FieldExpr;
  3002. if (fe != null && fe.IsMarshalByRefAccess (rc)) {
  3003. rc.Report.SymbolRelatedToPreviousError (me.DeclaringType);
  3004. rc.Report.Warning (1690, 1, loc,
  3005. "Cannot call methods, properties, or indexers on `{0}' because it is a value type member of a marshal-by-reference class",
  3006. me.GetSignatureForError ());
  3007. }
  3008. return true;
  3009. }
  3010. //
  3011. // Additional checks for l-value member access
  3012. //
  3013. if (rhs != null) {
  3014. if (InstanceExpression is UnboxCast) {
  3015. rc.Report.Error (445, InstanceExpression.Location, "Cannot modify the result of an unboxing conversion");
  3016. }
  3017. }
  3018. return true;
  3019. }
  3020. public virtual MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
  3021. {
  3022. if (left != null && !ConditionalAccess && left.IsNull && TypeSpec.IsReferenceType (left.Type)) {
  3023. ec.Report.Warning (1720, 1, left.Location,
  3024. "Expression will always cause a `{0}'", "System.NullReferenceException");
  3025. }
  3026. InstanceExpression = left;
  3027. return this;
  3028. }
  3029. protected void EmitInstance (EmitContext ec, bool prepare_for_load)
  3030. {
  3031. var inst = new InstanceEmitter (InstanceExpression, TypeSpec.IsValueType (InstanceExpression.Type));
  3032. inst.Emit (ec, ConditionalAccess);
  3033. if (prepare_for_load)
  3034. ec.Emit (OpCodes.Dup);
  3035. }
  3036. public abstract void SetTypeArguments (ResolveContext ec, TypeArguments ta);
  3037. }
  3038. public class ExtensionMethodCandidates
  3039. {
  3040. readonly NamespaceContainer container;
  3041. readonly IList<MethodSpec> methods;
  3042. readonly int index;
  3043. readonly IMemberContext context;
  3044. public ExtensionMethodCandidates (IMemberContext context, IList<MethodSpec> methods, NamespaceContainer nsContainer, int lookupIndex)
  3045. {
  3046. this.context = context;
  3047. this.methods = methods;
  3048. this.container = nsContainer;
  3049. this.index = lookupIndex;
  3050. }
  3051. public NamespaceContainer Container {
  3052. get {
  3053. return container;
  3054. }
  3055. }
  3056. public IMemberContext Context {
  3057. get {
  3058. return context;
  3059. }
  3060. }
  3061. public int LookupIndex {
  3062. get {
  3063. return index;
  3064. }
  3065. }
  3066. public IList<MethodSpec> Methods {
  3067. get {
  3068. return methods;
  3069. }
  3070. }
  3071. }
  3072. //
  3073. // Represents a group of extension method candidates for whole namespace
  3074. //
  3075. class ExtensionMethodGroupExpr : MethodGroupExpr, OverloadResolver.IErrorHandler
  3076. {
  3077. ExtensionMethodCandidates candidates;
  3078. public Expression ExtensionExpression;
  3079. public ExtensionMethodGroupExpr (ExtensionMethodCandidates candidates, Expression extensionExpr, Location loc)
  3080. : base (candidates.Methods.Cast<MemberSpec>().ToList (), extensionExpr.Type, loc)
  3081. {
  3082. this.candidates = candidates;
  3083. this.ExtensionExpression = extensionExpr;
  3084. }
  3085. public override bool IsStatic {
  3086. get { return true; }
  3087. }
  3088. public override void FlowAnalysis (FlowAnalysisContext fc)
  3089. {
  3090. if (ConditionalAccess) {
  3091. fc.BranchConditionalAccessDefiniteAssignment ();
  3092. }
  3093. }
  3094. //
  3095. // For extension methodgroup we are not looking for base members but parent
  3096. // namespace extension methods
  3097. //
  3098. public override IList<MemberSpec> GetBaseMembers (TypeSpec baseType)
  3099. {
  3100. // TODO: candidates are null only when doing error reporting, that's
  3101. // incorrect. We have to discover same extension methods in error mode
  3102. if (candidates == null)
  3103. return null;
  3104. int arity = type_arguments == null ? 0 : type_arguments.Count;
  3105. candidates = candidates.Container.LookupExtensionMethod (candidates.Context, ExtensionExpression.Type, Name, arity, candidates.LookupIndex);
  3106. if (candidates == null)
  3107. return null;
  3108. return candidates.Methods.Cast<MemberSpec> ().ToList ();
  3109. }
  3110. public override MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
  3111. {
  3112. // We are already here
  3113. return null;
  3114. }
  3115. public override MethodGroupExpr OverloadResolve (ResolveContext ec, ref Arguments arguments, OverloadResolver.IErrorHandler ehandler, OverloadResolver.Restrictions restr)
  3116. {
  3117. if (arguments == null)
  3118. arguments = new Arguments (1);
  3119. ExtensionExpression = ExtensionExpression.Resolve (ec);
  3120. if (ExtensionExpression == null)
  3121. return null;
  3122. var cand = candidates;
  3123. var atype = ConditionalAccess ? Argument.AType.ExtensionTypeConditionalAccess : Argument.AType.ExtensionType;
  3124. arguments.Insert (0, new Argument (ExtensionExpression, atype));
  3125. var res = base.OverloadResolve (ec, ref arguments, ehandler ?? this, restr);
  3126. // Restore candidates in case we are running in probing mode
  3127. candidates = cand;
  3128. // Store resolved argument and restore original arguments
  3129. if (res == null) {
  3130. // Clean-up modified arguments for error reporting
  3131. arguments.RemoveAt (0);
  3132. return null;
  3133. }
  3134. var me = ExtensionExpression as MemberExpr;
  3135. if (me != null) {
  3136. me.ResolveInstanceExpression (ec, null);
  3137. var fe = me as FieldExpr;
  3138. if (fe != null)
  3139. fe.Spec.MemberDefinition.SetIsUsed ();
  3140. }
  3141. InstanceExpression = null;
  3142. return this;
  3143. }
  3144. #region IErrorHandler Members
  3145. bool OverloadResolver.IErrorHandler.AmbiguousCandidates (ResolveContext rc, MemberSpec best, MemberSpec ambiguous)
  3146. {
  3147. return false;
  3148. }
  3149. bool OverloadResolver.IErrorHandler.ArgumentMismatch (ResolveContext rc, MemberSpec best, Argument arg, int index)
  3150. {
  3151. rc.Report.SymbolRelatedToPreviousError (best);
  3152. rc.Report.Error (1928, loc,
  3153. "Type `{0}' does not contain a member `{1}' and the best extension method overload `{2}' has some invalid arguments",
  3154. queried_type.GetSignatureForError (), Name, best.GetSignatureForError ());
  3155. if (index == 0) {
  3156. rc.Report.Error (1929, loc,
  3157. "Extension method instance type `{0}' cannot be converted to `{1}'",
  3158. arg.Type.GetSignatureForError (), ((MethodSpec)best).Parameters.ExtensionMethodType.GetSignatureForError ());
  3159. }
  3160. return true;
  3161. }
  3162. bool OverloadResolver.IErrorHandler.NoArgumentMatch (ResolveContext rc, MemberSpec best)
  3163. {
  3164. return false;
  3165. }
  3166. bool OverloadResolver.IErrorHandler.TypeInferenceFailed (ResolveContext rc, MemberSpec best)
  3167. {
  3168. return false;
  3169. }
  3170. #endregion
  3171. }
  3172. /// <summary>
  3173. /// MethodGroupExpr represents a group of method candidates which
  3174. /// can be resolved to the best method overload
  3175. /// </summary>
  3176. public class MethodGroupExpr : MemberExpr, OverloadResolver.IBaseMembersProvider
  3177. {
  3178. static readonly MemberSpec[] Excluded = new MemberSpec[0];
  3179. protected IList<MemberSpec> Methods;
  3180. MethodSpec best_candidate;
  3181. TypeSpec best_candidate_return;
  3182. protected TypeArguments type_arguments;
  3183. SimpleName simple_name;
  3184. protected TypeSpec queried_type;
  3185. public MethodGroupExpr (IList<MemberSpec> mi, TypeSpec type, Location loc)
  3186. {
  3187. Methods = mi;
  3188. this.loc = loc;
  3189. this.type = InternalType.MethodGroup;
  3190. eclass = ExprClass.MethodGroup;
  3191. queried_type = type;
  3192. }
  3193. public MethodGroupExpr (MethodSpec m, TypeSpec type, Location loc)
  3194. : this (new MemberSpec[] { m }, type, loc)
  3195. {
  3196. }
  3197. #region Properties
  3198. public MethodSpec BestCandidate {
  3199. get {
  3200. return best_candidate;
  3201. }
  3202. }
  3203. public TypeSpec BestCandidateReturnType {
  3204. get {
  3205. return best_candidate_return;
  3206. }
  3207. }
  3208. public IList<MemberSpec> Candidates {
  3209. get {
  3210. return Methods;
  3211. }
  3212. }
  3213. protected override TypeSpec DeclaringType {
  3214. get {
  3215. return queried_type;
  3216. }
  3217. }
  3218. public bool IsConditionallyExcluded {
  3219. get {
  3220. return Methods == Excluded;
  3221. }
  3222. }
  3223. public override bool IsInstance {
  3224. get {
  3225. if (best_candidate != null)
  3226. return !best_candidate.IsStatic;
  3227. return false;
  3228. }
  3229. }
  3230. public override bool IsSideEffectFree {
  3231. get {
  3232. return InstanceExpression == null || InstanceExpression.IsSideEffectFree;
  3233. }
  3234. }
  3235. public override bool IsStatic {
  3236. get {
  3237. if (best_candidate != null)
  3238. return best_candidate.IsStatic;
  3239. return false;
  3240. }
  3241. }
  3242. public override string KindName {
  3243. get { return "method"; }
  3244. }
  3245. public override string Name {
  3246. get {
  3247. if (best_candidate != null)
  3248. return best_candidate.Name;
  3249. // TODO: throw ?
  3250. return Methods.First ().Name;
  3251. }
  3252. }
  3253. #endregion
  3254. //
  3255. // When best candidate is already know this factory can be used
  3256. // to avoid expensive overload resolution to be called
  3257. //
  3258. // NOTE: InstanceExpression has to be set manually
  3259. //
  3260. public static MethodGroupExpr CreatePredefined (MethodSpec best, TypeSpec queriedType, Location loc)
  3261. {
  3262. return new MethodGroupExpr (best, queriedType, loc) {
  3263. best_candidate = best,
  3264. best_candidate_return = best.ReturnType
  3265. };
  3266. }
  3267. public override string GetSignatureForError ()
  3268. {
  3269. if (best_candidate != null)
  3270. return best_candidate.GetSignatureForError ();
  3271. return Methods.First ().GetSignatureForError ();
  3272. }
  3273. public override Expression CreateExpressionTree (ResolveContext ec)
  3274. {
  3275. if (best_candidate == null) {
  3276. ec.Report.Error (1953, loc, "An expression tree cannot contain an expression with method group");
  3277. return null;
  3278. }
  3279. if (IsConditionallyExcluded)
  3280. ec.Report.Error (765, loc,
  3281. "Partial methods with only a defining declaration or removed conditional methods cannot be used in an expression tree");
  3282. if (ConditionalAccess)
  3283. Error_NullShortCircuitInsideExpressionTree (ec);
  3284. return new TypeOfMethod (best_candidate, loc);
  3285. }
  3286. protected override Expression DoResolve (ResolveContext ec)
  3287. {
  3288. this.eclass = ExprClass.MethodGroup;
  3289. if (InstanceExpression != null) {
  3290. InstanceExpression = InstanceExpression.Resolve (ec);
  3291. if (InstanceExpression == null)
  3292. return null;
  3293. }
  3294. return this;
  3295. }
  3296. public override void Emit (EmitContext ec)
  3297. {
  3298. throw new NotSupportedException ();
  3299. }
  3300. public void EmitCall (EmitContext ec, Arguments arguments, bool statement)
  3301. {
  3302. var call = new CallEmitter ();
  3303. call.InstanceExpression = InstanceExpression;
  3304. call.ConditionalAccess = ConditionalAccess;
  3305. if (statement)
  3306. call.EmitStatement (ec, best_candidate, arguments, loc);
  3307. else
  3308. call.Emit (ec, best_candidate, arguments, loc);
  3309. }
  3310. public void EmitCall (EmitContext ec, Arguments arguments, TypeSpec conditionalAccessReceiver, bool statement)
  3311. {
  3312. ec.ConditionalAccess = new ConditionalAccessContext (conditionalAccessReceiver, ec.DefineLabel ()) {
  3313. Statement = statement
  3314. };
  3315. EmitCall (ec, arguments, statement);
  3316. ec.CloseConditionalAccess (!statement && best_candidate_return != conditionalAccessReceiver && conditionalAccessReceiver.IsNullableType ? conditionalAccessReceiver : null);
  3317. }
  3318. public override void Error_ValueCannotBeConverted (ResolveContext ec, TypeSpec target, bool expl)
  3319. {
  3320. ec.Report.Error (428, loc, "Cannot convert method group `{0}' to non-delegate type `{1}'. Consider using parentheses to invoke the method",
  3321. Name, target.GetSignatureForError ());
  3322. }
  3323. public static bool IsExtensionMethodArgument (Expression expr)
  3324. {
  3325. //
  3326. // LAMESPEC: No details about which expressions are not allowed
  3327. //
  3328. return !(expr is TypeExpr) && !(expr is BaseThis);
  3329. }
  3330. /// <summary>
  3331. /// Find the Applicable Function Members (7.4.2.1)
  3332. ///
  3333. /// me: Method Group expression with the members to select.
  3334. /// it might contain constructors or methods (or anything
  3335. /// that maps to a method).
  3336. ///
  3337. /// Arguments: ArrayList containing resolved Argument objects.
  3338. ///
  3339. /// loc: The location if we want an error to be reported, or a Null
  3340. /// location for "probing" purposes.
  3341. ///
  3342. /// Returns: The MethodBase (either a ConstructorInfo or a MethodInfo)
  3343. /// that is the best match of me on Arguments.
  3344. ///
  3345. /// </summary>
  3346. public virtual MethodGroupExpr OverloadResolve (ResolveContext ec, ref Arguments args, OverloadResolver.IErrorHandler cerrors, OverloadResolver.Restrictions restr)
  3347. {
  3348. // TODO: causes issues with probing mode, remove explicit Kind check
  3349. if (best_candidate != null && best_candidate.Kind == MemberKind.Destructor)
  3350. return this;
  3351. var r = new OverloadResolver (Methods, type_arguments, restr, loc);
  3352. if ((restr & OverloadResolver.Restrictions.NoBaseMembers) == 0) {
  3353. r.BaseMembersProvider = this;
  3354. r.InstanceQualifier = this;
  3355. }
  3356. if (cerrors != null)
  3357. r.CustomErrors = cerrors;
  3358. // TODO: When in probing mode do IsApplicable only and when called again do VerifyArguments for full error reporting
  3359. best_candidate = r.ResolveMember<MethodSpec> (ec, ref args);
  3360. if (best_candidate == null) {
  3361. if (!r.BestCandidateIsDynamic)
  3362. return null;
  3363. if (simple_name != null && ec.IsStatic)
  3364. InstanceExpression = ProbeIdenticalTypeName (ec, InstanceExpression, simple_name);
  3365. return this;
  3366. }
  3367. // Overload resolver had to create a new method group, all checks bellow have already been executed
  3368. if (r.BestCandidateNewMethodGroup != null)
  3369. return r.BestCandidateNewMethodGroup;
  3370. if (best_candidate.Kind == MemberKind.Method && (restr & OverloadResolver.Restrictions.ProbingOnly) == 0) {
  3371. if (InstanceExpression != null) {
  3372. if (best_candidate.IsExtensionMethod && args[0].Expr == InstanceExpression) {
  3373. InstanceExpression = null;
  3374. } else {
  3375. if (simple_name != null && best_candidate.IsStatic) {
  3376. InstanceExpression = ProbeIdenticalTypeName (ec, InstanceExpression, simple_name);
  3377. }
  3378. InstanceExpression.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup | ResolveFlags.Type);
  3379. }
  3380. }
  3381. ResolveInstanceExpression (ec, null);
  3382. }
  3383. var base_override = CandidateToBaseOverride (ec, best_candidate);
  3384. if (base_override == best_candidate) {
  3385. best_candidate_return = r.BestCandidateReturnType;
  3386. } else {
  3387. best_candidate = base_override;
  3388. best_candidate_return = best_candidate.ReturnType;
  3389. }
  3390. if (best_candidate.IsGeneric && (restr & OverloadResolver.Restrictions.ProbingOnly) == 0 && TypeParameterSpec.HasAnyTypeParameterConstrained (best_candidate.GenericDefinition)) {
  3391. ConstraintChecker cc = new ConstraintChecker (ec);
  3392. cc.CheckAll (best_candidate.GetGenericMethodDefinition (), best_candidate.TypeArguments, best_candidate.Constraints, loc);
  3393. }
  3394. //
  3395. // Additional check for possible imported base override method which
  3396. // could not be done during IsOverrideMethodBaseTypeAccessible
  3397. //
  3398. if (best_candidate.IsVirtual && (best_candidate.DeclaringType.Modifiers & Modifiers.PROTECTED) != 0 &&
  3399. best_candidate.MemberDefinition.IsImported && !best_candidate.DeclaringType.IsAccessible (ec)) {
  3400. ec.Report.SymbolRelatedToPreviousError (best_candidate);
  3401. ErrorIsInaccesible (ec, best_candidate.GetSignatureForError (), loc);
  3402. }
  3403. // Speed up the check by not doing it on disallowed targets
  3404. if (best_candidate_return.Kind == MemberKind.Void && best_candidate.IsConditionallyExcluded (ec))
  3405. Methods = Excluded;
  3406. return this;
  3407. }
  3408. public override MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
  3409. {
  3410. var fe = left as FieldExpr;
  3411. if (fe != null) {
  3412. //
  3413. // Using method-group on struct fields makes the struct assigned. I am not sure
  3414. // why but that's what .net does
  3415. //
  3416. fe.Spec.MemberDefinition.SetIsAssigned ();
  3417. }
  3418. simple_name = original;
  3419. return base.ResolveMemberAccess (ec, left, original);
  3420. }
  3421. public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
  3422. {
  3423. type_arguments = ta;
  3424. }
  3425. #region IBaseMembersProvider Members
  3426. public virtual IList<MemberSpec> GetBaseMembers (TypeSpec baseType)
  3427. {
  3428. return baseType == null ? null : MemberCache.FindMembers (baseType, Methods [0].Name, false);
  3429. }
  3430. public IParametersMember GetOverrideMemberParameters (MemberSpec member)
  3431. {
  3432. if (queried_type == member.DeclaringType)
  3433. return null;
  3434. return MemberCache.FindMember (queried_type, new MemberFilter ((MethodSpec) member),
  3435. BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as IParametersMember;
  3436. }
  3437. //
  3438. // Extension methods lookup after ordinary methods candidates failed to apply
  3439. //
  3440. public virtual MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
  3441. {
  3442. if (InstanceExpression == null || InstanceExpression.eclass == ExprClass.Type)
  3443. return null;
  3444. if (!IsExtensionMethodArgument (InstanceExpression))
  3445. return null;
  3446. int arity = type_arguments == null ? 0 : type_arguments.Count;
  3447. var methods = rc.LookupExtensionMethod (InstanceExpression.Type, Methods[0].Name, arity);
  3448. if (methods == null)
  3449. return null;
  3450. var emg = new ExtensionMethodGroupExpr (methods, InstanceExpression, loc);
  3451. emg.SetTypeArguments (rc, type_arguments);
  3452. return emg;
  3453. }
  3454. #endregion
  3455. }
  3456. struct ConstructorInstanceQualifier : OverloadResolver.IInstanceQualifier
  3457. {
  3458. public ConstructorInstanceQualifier (TypeSpec type)
  3459. : this ()
  3460. {
  3461. InstanceType = type;
  3462. }
  3463. public TypeSpec InstanceType { get; private set; }
  3464. public bool CheckProtectedMemberAccess (ResolveContext rc, MemberSpec member)
  3465. {
  3466. return MemberExpr.CheckProtectedMemberAccess (rc, member, InstanceType);
  3467. }
  3468. }
  3469. public struct OverloadResolver
  3470. {
  3471. [Flags]
  3472. public enum Restrictions
  3473. {
  3474. None = 0,
  3475. DelegateInvoke = 1,
  3476. ProbingOnly = 1 << 1,
  3477. CovariantDelegate = 1 << 2,
  3478. NoBaseMembers = 1 << 3,
  3479. BaseMembersIncluded = 1 << 4,
  3480. GetEnumeratorLookup = 1 << 5
  3481. }
  3482. public interface IBaseMembersProvider
  3483. {
  3484. IList<MemberSpec> GetBaseMembers (TypeSpec baseType);
  3485. IParametersMember GetOverrideMemberParameters (MemberSpec member);
  3486. MethodGroupExpr LookupExtensionMethod (ResolveContext rc);
  3487. }
  3488. public interface IErrorHandler
  3489. {
  3490. bool AmbiguousCandidates (ResolveContext rc, MemberSpec best, MemberSpec ambiguous);
  3491. bool ArgumentMismatch (ResolveContext rc, MemberSpec best, Argument a, int index);
  3492. bool NoArgumentMatch (ResolveContext rc, MemberSpec best);
  3493. bool TypeInferenceFailed (ResolveContext rc, MemberSpec best);
  3494. }
  3495. public interface IInstanceQualifier
  3496. {
  3497. TypeSpec InstanceType { get; }
  3498. bool CheckProtectedMemberAccess (ResolveContext rc, MemberSpec member);
  3499. }
  3500. sealed class NoBaseMembers : IBaseMembersProvider
  3501. {
  3502. public static readonly IBaseMembersProvider Instance = new NoBaseMembers ();
  3503. public IList<MemberSpec> GetBaseMembers (TypeSpec baseType)
  3504. {
  3505. return null;
  3506. }
  3507. public IParametersMember GetOverrideMemberParameters (MemberSpec member)
  3508. {
  3509. return null;
  3510. }
  3511. public MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
  3512. {
  3513. return null;
  3514. }
  3515. }
  3516. struct AmbiguousCandidate
  3517. {
  3518. public readonly MemberSpec Member;
  3519. public readonly bool Expanded;
  3520. public readonly AParametersCollection Parameters;
  3521. public AmbiguousCandidate (MemberSpec member, AParametersCollection parameters, bool expanded)
  3522. {
  3523. Member = member;
  3524. Parameters = parameters;
  3525. Expanded = expanded;
  3526. }
  3527. }
  3528. Location loc;
  3529. IList<MemberSpec> members;
  3530. TypeArguments type_arguments;
  3531. IBaseMembersProvider base_provider;
  3532. IErrorHandler custom_errors;
  3533. IInstanceQualifier instance_qualifier;
  3534. Restrictions restrictions;
  3535. MethodGroupExpr best_candidate_extension_group;
  3536. TypeSpec best_candidate_return_type;
  3537. SessionReportPrinter lambda_conv_msgs;
  3538. public OverloadResolver (IList<MemberSpec> members, Restrictions restrictions, Location loc)
  3539. : this (members, null, restrictions, loc)
  3540. {
  3541. }
  3542. public OverloadResolver (IList<MemberSpec> members, TypeArguments targs, Restrictions restrictions, Location loc)
  3543. : this ()
  3544. {
  3545. if (members == null || members.Count == 0)
  3546. throw new ArgumentException ("empty members set");
  3547. this.members = members;
  3548. this.loc = loc;
  3549. type_arguments = targs;
  3550. this.restrictions = restrictions;
  3551. if (IsDelegateInvoke)
  3552. this.restrictions |= Restrictions.NoBaseMembers;
  3553. base_provider = NoBaseMembers.Instance;
  3554. }
  3555. #region Properties
  3556. public IBaseMembersProvider BaseMembersProvider {
  3557. get {
  3558. return base_provider;
  3559. }
  3560. set {
  3561. base_provider = value;
  3562. }
  3563. }
  3564. public bool BestCandidateIsDynamic { get; set; }
  3565. //
  3566. // Best candidate was found in newly created MethodGroupExpr, used by extension methods
  3567. //
  3568. public MethodGroupExpr BestCandidateNewMethodGroup {
  3569. get {
  3570. return best_candidate_extension_group;
  3571. }
  3572. }
  3573. //
  3574. // Return type can be different between best candidate and closest override
  3575. //
  3576. public TypeSpec BestCandidateReturnType {
  3577. get {
  3578. return best_candidate_return_type;
  3579. }
  3580. }
  3581. public IErrorHandler CustomErrors {
  3582. get {
  3583. return custom_errors;
  3584. }
  3585. set {
  3586. custom_errors = value;
  3587. }
  3588. }
  3589. TypeSpec DelegateType {
  3590. get {
  3591. if ((restrictions & Restrictions.DelegateInvoke) == 0)
  3592. throw new InternalErrorException ("Not running in delegate mode", loc);
  3593. return members [0].DeclaringType;
  3594. }
  3595. }
  3596. public IInstanceQualifier InstanceQualifier {
  3597. get {
  3598. return instance_qualifier;
  3599. }
  3600. set {
  3601. instance_qualifier = value;
  3602. }
  3603. }
  3604. bool IsProbingOnly {
  3605. get {
  3606. return (restrictions & Restrictions.ProbingOnly) != 0;
  3607. }
  3608. }
  3609. bool IsDelegateInvoke {
  3610. get {
  3611. return (restrictions & Restrictions.DelegateInvoke) != 0;
  3612. }
  3613. }
  3614. #endregion
  3615. //
  3616. // 7.4.3.3 Better conversion from expression
  3617. // Returns : 1 if a->p is better,
  3618. // 2 if a->q is better,
  3619. // 0 if neither is better
  3620. //
  3621. static int BetterExpressionConversion (ResolveContext ec, Argument a, TypeSpec p, TypeSpec q)
  3622. {
  3623. TypeSpec argument_type = a.Type;
  3624. //
  3625. // If argument is an anonymous function
  3626. //
  3627. if (argument_type == InternalType.AnonymousMethod && ec.Module.Compiler.Settings.Version > LanguageVersion.ISO_2) {
  3628. //
  3629. // p and q are delegate types or expression tree types
  3630. //
  3631. if (p.IsExpressionTreeType || q.IsExpressionTreeType) {
  3632. if (q.MemberDefinition != p.MemberDefinition) {
  3633. return 0;
  3634. }
  3635. //
  3636. // Uwrap delegate from Expression<T>
  3637. //
  3638. q = TypeManager.GetTypeArguments (q)[0];
  3639. p = TypeManager.GetTypeArguments (p)[0];
  3640. }
  3641. var p_m = Delegate.GetInvokeMethod (p);
  3642. var q_m = Delegate.GetInvokeMethod (q);
  3643. //
  3644. // With identical parameter lists
  3645. //
  3646. if (!TypeSpecComparer.Equals (p_m.Parameters.Types, q_m.Parameters.Types))
  3647. return 0;
  3648. p = p_m.ReturnType;
  3649. var orig_q = q;
  3650. q = q_m.ReturnType;
  3651. //
  3652. // if p is void returning, and q has a return type Y, then C2 is the better conversion.
  3653. //
  3654. if (p.Kind == MemberKind.Void) {
  3655. return q.Kind != MemberKind.Void ? 2 : 0;
  3656. }
  3657. //
  3658. // if p has a return type Y, and q is void returning, then C1 is the better conversion.
  3659. //
  3660. if (q.Kind == MemberKind.Void) {
  3661. return p.Kind != MemberKind.Void ? 1: 0;
  3662. }
  3663. var am = (AnonymousMethodExpression) a.Expr;
  3664. //
  3665. // When anonymous method is an asynchronous, and P has a return type Task<Y1>, and Q has a return type Task<Y2>
  3666. // better conversion is performed between underlying types Y1 and Y2
  3667. //
  3668. if (p.IsGenericTask || q.IsGenericTask) {
  3669. if (am.Block.IsAsync && p.IsGenericTask && q.IsGenericTask) {
  3670. q = q.TypeArguments[0];
  3671. p = p.TypeArguments[0];
  3672. }
  3673. }
  3674. if (q != p) {
  3675. //
  3676. // An inferred return type X exists for E in the context of that parameter list, and
  3677. // the conversion from X to Y1 is better than the conversion from X to Y2
  3678. //
  3679. argument_type = am.InferReturnType (ec, null, orig_q);
  3680. if (argument_type == null) {
  3681. // TODO: Can this be hit?
  3682. return 1;
  3683. }
  3684. if (argument_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
  3685. argument_type = ec.BuiltinTypes.Object;
  3686. }
  3687. }
  3688. if (argument_type == p)
  3689. return 1;
  3690. if (argument_type == q)
  3691. return 2;
  3692. //
  3693. // The parameters are identicial and return type is not void, use better type conversion
  3694. // on return type to determine better one
  3695. //
  3696. return BetterTypeConversion (ec, p, q);
  3697. }
  3698. //
  3699. // 7.4.3.4 Better conversion from type
  3700. //
  3701. public static int BetterTypeConversion (ResolveContext ec, TypeSpec p, TypeSpec q)
  3702. {
  3703. if (p == null || q == null)
  3704. throw new InternalErrorException ("BetterTypeConversion got a null conversion");
  3705. switch (p.BuiltinType) {
  3706. case BuiltinTypeSpec.Type.Int:
  3707. if (q.BuiltinType == BuiltinTypeSpec.Type.UInt || q.BuiltinType == BuiltinTypeSpec.Type.ULong)
  3708. return 1;
  3709. break;
  3710. case BuiltinTypeSpec.Type.Long:
  3711. if (q.BuiltinType == BuiltinTypeSpec.Type.ULong)
  3712. return 1;
  3713. break;
  3714. case BuiltinTypeSpec.Type.SByte:
  3715. switch (q.BuiltinType) {
  3716. case BuiltinTypeSpec.Type.Byte:
  3717. case BuiltinTypeSpec.Type.UShort:
  3718. case BuiltinTypeSpec.Type.UInt:
  3719. case BuiltinTypeSpec.Type.ULong:
  3720. return 1;
  3721. }
  3722. break;
  3723. case BuiltinTypeSpec.Type.Short:
  3724. switch (q.BuiltinType) {
  3725. case BuiltinTypeSpec.Type.UShort:
  3726. case BuiltinTypeSpec.Type.UInt:
  3727. case BuiltinTypeSpec.Type.ULong:
  3728. return 1;
  3729. }
  3730. break;
  3731. case BuiltinTypeSpec.Type.Dynamic:
  3732. // Dynamic is never better
  3733. return 2;
  3734. }
  3735. switch (q.BuiltinType) {
  3736. case BuiltinTypeSpec.Type.Int:
  3737. if (p.BuiltinType == BuiltinTypeSpec.Type.UInt || p.BuiltinType == BuiltinTypeSpec.Type.ULong)
  3738. return 2;
  3739. break;
  3740. case BuiltinTypeSpec.Type.Long:
  3741. if (p.BuiltinType == BuiltinTypeSpec.Type.ULong)
  3742. return 2;
  3743. break;
  3744. case BuiltinTypeSpec.Type.SByte:
  3745. switch (p.BuiltinType) {
  3746. case BuiltinTypeSpec.Type.Byte:
  3747. case BuiltinTypeSpec.Type.UShort:
  3748. case BuiltinTypeSpec.Type.UInt:
  3749. case BuiltinTypeSpec.Type.ULong:
  3750. return 2;
  3751. }
  3752. break;
  3753. case BuiltinTypeSpec.Type.Short:
  3754. switch (p.BuiltinType) {
  3755. case BuiltinTypeSpec.Type.UShort:
  3756. case BuiltinTypeSpec.Type.UInt:
  3757. case BuiltinTypeSpec.Type.ULong:
  3758. return 2;
  3759. }
  3760. break;
  3761. case BuiltinTypeSpec.Type.Dynamic:
  3762. // Dynamic is never better
  3763. return 1;
  3764. }
  3765. // FIXME: handle lifted operators
  3766. // TODO: this is expensive
  3767. Expression p_tmp = new EmptyExpression (p);
  3768. Expression q_tmp = new EmptyExpression (q);
  3769. bool p_to_q = Convert.ImplicitConversionExists (ec, p_tmp, q);
  3770. bool q_to_p = Convert.ImplicitConversionExists (ec, q_tmp, p);
  3771. if (p_to_q && !q_to_p)
  3772. return 1;
  3773. if (q_to_p && !p_to_q)
  3774. return 2;
  3775. return 0;
  3776. }
  3777. /// <summary>
  3778. /// Determines "Better function" between candidate
  3779. /// and the current best match
  3780. /// </summary>
  3781. /// <remarks>
  3782. /// Returns a boolean indicating :
  3783. /// false if candidate ain't better
  3784. /// true if candidate is better than the current best match
  3785. /// </remarks>
  3786. static bool BetterFunction (ResolveContext ec, Arguments args, MemberSpec candidate, AParametersCollection cparam, bool candidate_params,
  3787. MemberSpec best, AParametersCollection bparam, bool best_params)
  3788. {
  3789. AParametersCollection candidate_pd = ((IParametersMember) candidate).Parameters;
  3790. AParametersCollection best_pd = ((IParametersMember) best).Parameters;
  3791. bool better_at_least_one = false;
  3792. bool are_equivalent = true;
  3793. int args_count = args == null ? 0 : args.Count;
  3794. int j = 0;
  3795. Argument a = null;
  3796. TypeSpec ct, bt;
  3797. for (int c_idx = 0, b_idx = 0; j < args_count; ++j, ++c_idx, ++b_idx) {
  3798. a = args[j];
  3799. // Default arguments are ignored for better decision
  3800. if (a.IsDefaultArgument)
  3801. break;
  3802. //
  3803. // When comparing named argument the parameter type index has to be looked up
  3804. // in original parameter set (override version for virtual members)
  3805. //
  3806. NamedArgument na = a as NamedArgument;
  3807. if (na != null) {
  3808. int idx = cparam.GetParameterIndexByName (na.Name);
  3809. ct = candidate_pd.Types[idx];
  3810. if (candidate_params && candidate_pd.FixedParameters[idx].ModFlags == Parameter.Modifier.PARAMS)
  3811. ct = TypeManager.GetElementType (ct);
  3812. idx = bparam.GetParameterIndexByName (na.Name);
  3813. bt = best_pd.Types[idx];
  3814. if (best_params && best_pd.FixedParameters[idx].ModFlags == Parameter.Modifier.PARAMS)
  3815. bt = TypeManager.GetElementType (bt);
  3816. } else {
  3817. ct = candidate_pd.Types[c_idx];
  3818. bt = best_pd.Types[b_idx];
  3819. if (candidate_params && candidate_pd.FixedParameters[c_idx].ModFlags == Parameter.Modifier.PARAMS) {
  3820. ct = TypeManager.GetElementType (ct);
  3821. --c_idx;
  3822. }
  3823. if (best_params && best_pd.FixedParameters[b_idx].ModFlags == Parameter.Modifier.PARAMS) {
  3824. bt = TypeManager.GetElementType (bt);
  3825. --b_idx;
  3826. }
  3827. }
  3828. if (TypeSpecComparer.IsEqual (ct, bt))
  3829. continue;
  3830. are_equivalent = false;
  3831. int result = BetterExpressionConversion (ec, a, ct, bt);
  3832. // for each argument, the conversion to 'ct' should be no worse than
  3833. // the conversion to 'bt'.
  3834. if (result == 2)
  3835. return false;
  3836. // for at least one argument, the conversion to 'ct' should be better than
  3837. // the conversion to 'bt'.
  3838. if (result != 0)
  3839. better_at_least_one = true;
  3840. }
  3841. if (better_at_least_one)
  3842. return true;
  3843. //
  3844. // Tie-breaking rules are applied only for equivalent parameter types
  3845. //
  3846. if (!are_equivalent)
  3847. return false;
  3848. //
  3849. // If candidate is applicable in its normal form and best has a params array and is applicable
  3850. // only in its expanded form, then candidate is better
  3851. //
  3852. if (candidate_params != best_params)
  3853. return !candidate_params;
  3854. //
  3855. // We have not reached end of parameters list due to params or used default parameters
  3856. //
  3857. while (j < candidate_pd.Count && j < best_pd.Count) {
  3858. var cand_param = candidate_pd.FixedParameters [j];
  3859. var best_param = best_pd.FixedParameters [j];
  3860. if (candidate_pd.Count == best_pd.Count) {
  3861. //
  3862. // LAMESPEC:
  3863. //
  3864. // void Foo (int i = 0) is better than void Foo (params int[]) for Foo ()
  3865. // void Foo (string[] s, string value = null) is better than Foo (string s, params string[]) for Foo (null) or Foo ()
  3866. //
  3867. if (cand_param.HasDefaultValue != best_param.HasDefaultValue)
  3868. return cand_param.HasDefaultValue;
  3869. if (cand_param.HasDefaultValue) {
  3870. ++j;
  3871. continue;
  3872. }
  3873. } else {
  3874. //
  3875. // Neither is better when not all arguments are provided
  3876. //
  3877. // void Foo (string s, int i = 0) <-> Foo (string s, int i = 0, int i2 = 0)
  3878. // void Foo (string s, int i = 0) <-> Foo (string s, byte i = 0)
  3879. // void Foo (string s, params int[]) <-> Foo (string s, params byte[])
  3880. //
  3881. if (cand_param.HasDefaultValue && best_param.HasDefaultValue)
  3882. return false;
  3883. }
  3884. break;
  3885. }
  3886. if (candidate_pd.Count != best_pd.Count)
  3887. return candidate_pd.Count < best_pd.Count;
  3888. //
  3889. // One is a non-generic method and second is a generic method, then non-generic is better
  3890. //
  3891. if (best.IsGeneric != candidate.IsGeneric)
  3892. return best.IsGeneric;
  3893. //
  3894. // Both methods have the same number of parameters, and the parameters have equal types
  3895. // Pick the "more specific" signature using rules over original (non-inflated) types
  3896. //
  3897. var candidate_def_pd = ((IParametersMember) candidate.MemberDefinition).Parameters;
  3898. var best_def_pd = ((IParametersMember) best.MemberDefinition).Parameters;
  3899. bool specific_at_least_once = false;
  3900. for (j = 0; j < args_count; ++j) {
  3901. NamedArgument na = args_count == 0 ? null : args [j] as NamedArgument;
  3902. if (na != null) {
  3903. ct = candidate_def_pd.Types[cparam.GetParameterIndexByName (na.Name)];
  3904. bt = best_def_pd.Types[bparam.GetParameterIndexByName (na.Name)];
  3905. } else {
  3906. ct = candidate_def_pd.Types[j];
  3907. bt = best_def_pd.Types[j];
  3908. }
  3909. if (ct == bt)
  3910. continue;
  3911. TypeSpec specific = MoreSpecific (ct, bt);
  3912. if (specific == bt)
  3913. return false;
  3914. if (specific == ct)
  3915. specific_at_least_once = true;
  3916. }
  3917. if (specific_at_least_once)
  3918. return true;
  3919. return false;
  3920. }
  3921. static bool CheckInflatedArguments (MethodSpec ms)
  3922. {
  3923. if (!TypeParameterSpec.HasAnyTypeParameterTypeConstrained (ms.GenericDefinition))
  3924. return true;
  3925. // Setup constraint checker for probing only
  3926. ConstraintChecker cc = new ConstraintChecker (null);
  3927. var mp = ms.Parameters.Types;
  3928. for (int i = 0; i < mp.Length; ++i) {
  3929. var type = mp[i] as InflatedTypeSpec;
  3930. if (type == null)
  3931. continue;
  3932. var targs = type.TypeArguments;
  3933. if (targs.Length == 0)
  3934. continue;
  3935. // TODO: Checking inflated MVAR arguments should be enough
  3936. if (!cc.CheckAll (type.GetDefinition (), targs, type.Constraints, Location.Null))
  3937. return false;
  3938. }
  3939. return true;
  3940. }
  3941. public static void Error_ConstructorMismatch (ResolveContext rc, TypeSpec type, int argCount, Location loc)
  3942. {
  3943. rc.Report.Error (1729, loc,
  3944. "The type `{0}' does not contain a constructor that takes `{1}' arguments",
  3945. type.GetSignatureForError (), argCount.ToString ());
  3946. }
  3947. //
  3948. // Determines if the candidate method is applicable to the given set of arguments
  3949. // There could be two different set of parameters for same candidate where one
  3950. // is the closest override for default values and named arguments checks and second
  3951. // one being the virtual base for the parameter types and modifiers.
  3952. //
  3953. // A return value rates candidate method compatibility,
  3954. // 0 = the best, int.MaxValue = the worst
  3955. // -1 = fatal error
  3956. //
  3957. int IsApplicable (ResolveContext ec, ref Arguments arguments, int arg_count, ref MemberSpec candidate, IParametersMember pm, ref bool params_expanded_form, ref bool dynamicArgument, ref TypeSpec returnType, bool errorMode)
  3958. {
  3959. // Parameters of most-derived type used mainly for named and optional parameters
  3960. var pd = pm.Parameters;
  3961. // Used for params modifier only, that's legacy of C# 1.0 which uses base type for
  3962. // params modifier instead of most-derived type
  3963. var cpd = ((IParametersMember) candidate).Parameters;
  3964. int param_count = pd.Count;
  3965. int optional_count = 0;
  3966. int score;
  3967. Arguments orig_args = arguments;
  3968. if (arg_count != param_count) {
  3969. //
  3970. // No arguments expansion when doing exact match for delegates
  3971. //
  3972. if ((restrictions & Restrictions.CovariantDelegate) == 0) {
  3973. for (int i = 0; i < pd.Count; ++i) {
  3974. if (pd.FixedParameters[i].HasDefaultValue) {
  3975. optional_count = pd.Count - i;
  3976. break;
  3977. }
  3978. }
  3979. }
  3980. if (optional_count != 0) {
  3981. // Readjust expected number when params used
  3982. if (cpd.HasParams) {
  3983. optional_count--;
  3984. if (arg_count < param_count)
  3985. param_count--;
  3986. } else if (arg_count > param_count) {
  3987. int args_gap = System.Math.Abs (arg_count - param_count);
  3988. return int.MaxValue - 10000 + args_gap;
  3989. } else if (arg_count < param_count - optional_count) {
  3990. int args_gap = System.Math.Abs (param_count - optional_count - arg_count);
  3991. return int.MaxValue - 10000 + args_gap;
  3992. }
  3993. } else if (arg_count != param_count) {
  3994. int args_gap = System.Math.Abs (arg_count - param_count);
  3995. if (!cpd.HasParams)
  3996. return int.MaxValue - 10000 + args_gap;
  3997. if (arg_count < param_count - 1)
  3998. return int.MaxValue - 10000 + args_gap;
  3999. }
  4000. // Resize to fit optional arguments
  4001. if (optional_count != 0) {
  4002. if (arguments == null) {
  4003. arguments = new Arguments (optional_count);
  4004. } else {
  4005. // Have to create a new container, so the next run can do same
  4006. var resized = new Arguments (param_count);
  4007. resized.AddRange (arguments);
  4008. arguments = resized;
  4009. }
  4010. for (int i = arg_count; i < param_count; ++i)
  4011. arguments.Add (null);
  4012. }
  4013. }
  4014. if (arg_count > 0) {
  4015. //
  4016. // Shuffle named arguments to the right positions if there are any
  4017. //
  4018. if (arguments[arg_count - 1] is NamedArgument) {
  4019. arg_count = arguments.Count;
  4020. for (int i = 0; i < arg_count; ++i) {
  4021. bool arg_moved = false;
  4022. while (true) {
  4023. NamedArgument na = arguments[i] as NamedArgument;
  4024. if (na == null)
  4025. break;
  4026. int index = pd.GetParameterIndexByName (na.Name);
  4027. // Named parameter not found
  4028. if (index < 0)
  4029. return (i + 1) * 3;
  4030. // already reordered
  4031. if (index == i)
  4032. break;
  4033. Argument temp;
  4034. if (index >= param_count) {
  4035. // When using parameters which should not be available to the user
  4036. if ((cpd.FixedParameters[index].ModFlags & Parameter.Modifier.PARAMS) == 0)
  4037. break;
  4038. arguments.Add (null);
  4039. ++arg_count;
  4040. temp = null;
  4041. } else {
  4042. if (index == arg_count)
  4043. return (i + 1) * 3;
  4044. temp = arguments [index];
  4045. // The slot has been taken by positional argument
  4046. if (temp != null && !(temp is NamedArgument))
  4047. break;
  4048. }
  4049. if (!arg_moved) {
  4050. arguments = arguments.MarkOrderedArgument (na);
  4051. arg_moved = true;
  4052. }
  4053. if (arguments == orig_args) {
  4054. arguments = new Arguments (orig_args.Count);
  4055. arguments.AddRange (orig_args);
  4056. }
  4057. arguments[index] = arguments[i];
  4058. arguments[i] = temp;
  4059. if (temp == null)
  4060. break;
  4061. }
  4062. }
  4063. } else {
  4064. arg_count = arguments.Count;
  4065. }
  4066. } else if (arguments != null) {
  4067. arg_count = arguments.Count;
  4068. }
  4069. //
  4070. // Don't do any expensive checks when the candidate cannot succeed
  4071. //
  4072. if (arg_count != param_count && !cpd.HasParams)
  4073. return (param_count - arg_count) * 2 + 1;
  4074. var dep = candidate.GetMissingDependencies ();
  4075. if (dep != null) {
  4076. ImportedTypeDefinition.Error_MissingDependency (ec, dep, loc);
  4077. return -1;
  4078. }
  4079. //
  4080. // 1. Handle generic method using type arguments when specified or type inference
  4081. //
  4082. TypeSpec[] ptypes;
  4083. var ms = candidate as MethodSpec;
  4084. if (ms != null && ms.IsGeneric) {
  4085. if (type_arguments != null) {
  4086. var g_args_count = ms.Arity;
  4087. if (g_args_count != type_arguments.Count)
  4088. return int.MaxValue - 20000 + System.Math.Abs (type_arguments.Count - g_args_count);
  4089. if (type_arguments.Arguments != null)
  4090. ms = ms.MakeGenericMethod (ec, type_arguments.Arguments);
  4091. } else {
  4092. //
  4093. // Deploy custom error reporting for infered anonymous expression or lambda methods. When
  4094. // probing lambda methods keep all errors reported in separate set and once we are done and no best
  4095. // candidate was found use the set to report more details about what was wrong with lambda body.
  4096. // The general idea is to distinguish between code errors and errors caused by
  4097. // trial-and-error type inference
  4098. //
  4099. if (lambda_conv_msgs == null) {
  4100. for (int i = 0; i < arg_count; i++) {
  4101. Argument a = arguments[i];
  4102. if (a == null)
  4103. continue;
  4104. var am = a.Expr as AnonymousMethodExpression;
  4105. if (am != null) {
  4106. if (lambda_conv_msgs == null)
  4107. lambda_conv_msgs = new SessionReportPrinter ();
  4108. am.TypeInferenceReportPrinter = lambda_conv_msgs;
  4109. }
  4110. }
  4111. }
  4112. var ti = new TypeInference (arguments);
  4113. TypeSpec[] i_args = ti.InferMethodArguments (ec, ms);
  4114. if (i_args == null)
  4115. return ti.InferenceScore - 20000;
  4116. //
  4117. // Clear any error messages when the result was success
  4118. //
  4119. if (lambda_conv_msgs != null)
  4120. lambda_conv_msgs.ClearSession ();
  4121. if (i_args.Length != 0) {
  4122. if (!errorMode) {
  4123. foreach (var ta in i_args) {
  4124. if (!ta.IsAccessible (ec))
  4125. return ti.InferenceScore - 10000;
  4126. }
  4127. }
  4128. ms = ms.MakeGenericMethod (ec, i_args);
  4129. }
  4130. }
  4131. //
  4132. // Type arguments constraints have to match for the method to be applicable
  4133. //
  4134. if (!CheckInflatedArguments (ms)) {
  4135. candidate = ms;
  4136. return int.MaxValue - 25000;
  4137. }
  4138. //
  4139. // We have a generic return type and at same time the method is override which
  4140. // means we have to also inflate override return type in case the candidate is
  4141. // best candidate and override return type is different to base return type.
  4142. //
  4143. // virtual Foo<T, object> with override Foo<T, dynamic>
  4144. //
  4145. if (candidate != pm) {
  4146. MethodSpec override_ms = (MethodSpec) pm;
  4147. var inflator = new TypeParameterInflator (ec, ms.DeclaringType, override_ms.GenericDefinition.TypeParameters, ms.TypeArguments);
  4148. returnType = inflator.Inflate (returnType);
  4149. } else {
  4150. returnType = ms.ReturnType;
  4151. }
  4152. candidate = ms;
  4153. pd = ms.Parameters;
  4154. ptypes = pd.Types;
  4155. } else {
  4156. if (type_arguments != null)
  4157. return int.MaxValue - 15000;
  4158. ptypes = cpd.Types;
  4159. }
  4160. //
  4161. // 2. Each argument has to be implicitly convertible to method parameter
  4162. //
  4163. Parameter.Modifier p_mod = 0;
  4164. TypeSpec pt = null;
  4165. for (int i = 0; i < arg_count; i++) {
  4166. Argument a = arguments[i];
  4167. if (a == null) {
  4168. var fp = pd.FixedParameters[i];
  4169. if (!fp.HasDefaultValue) {
  4170. arguments = orig_args;
  4171. return arg_count * 2 + 2;
  4172. }
  4173. //
  4174. // Get the default value expression, we can use the same expression
  4175. // if the type matches
  4176. //
  4177. Expression e = fp.DefaultValue;
  4178. if (e != null) {
  4179. e = ResolveDefaultValueArgument (ec, ptypes[i], e, loc);
  4180. if (e == null) {
  4181. // Restore for possible error reporting
  4182. for (int ii = i; ii < arg_count; ++ii)
  4183. arguments.RemoveAt (i);
  4184. return (arg_count - i) * 2 + 1;
  4185. }
  4186. }
  4187. if ((fp.ModFlags & Parameter.Modifier.CallerMask) != 0) {
  4188. //
  4189. // LAMESPEC: Attributes can be mixed together with build-in priority
  4190. //
  4191. if ((fp.ModFlags & Parameter.Modifier.CallerLineNumber) != 0) {
  4192. e = new IntLiteral (ec.BuiltinTypes, loc.Row, loc);
  4193. } else if ((fp.ModFlags & Parameter.Modifier.CallerFilePath) != 0) {
  4194. e = new StringLiteral (ec.BuiltinTypes, loc.NameFullPath, loc);
  4195. } else if (ec.MemberContext.CurrentMemberDefinition != null) {
  4196. e = new StringLiteral (ec.BuiltinTypes, ec.MemberContext.CurrentMemberDefinition.GetCallerMemberName (), loc);
  4197. }
  4198. }
  4199. arguments[i] = new Argument (e, Argument.AType.Default);
  4200. continue;
  4201. }
  4202. if (p_mod != Parameter.Modifier.PARAMS) {
  4203. p_mod = (pd.FixedParameters[i].ModFlags & ~Parameter.Modifier.PARAMS) | (cpd.FixedParameters[i].ModFlags & Parameter.Modifier.PARAMS);
  4204. pt = ptypes [i];
  4205. } else if (!params_expanded_form) {
  4206. params_expanded_form = true;
  4207. pt = ((ElementTypeSpec) pt).Element;
  4208. i -= 2;
  4209. continue;
  4210. }
  4211. score = 1;
  4212. if (!params_expanded_form) {
  4213. if (a.IsExtensionType) {
  4214. //
  4215. // Indentity, implicit reference or boxing conversion must exist for the extension parameter
  4216. //
  4217. // LAMESPEC: or implicit type parameter conversion
  4218. //
  4219. var at = a.Type;
  4220. if (at == pt || TypeSpecComparer.IsEqual (at, pt) ||
  4221. Convert.ImplicitReferenceConversionExists (at, pt, false) ||
  4222. Convert.ImplicitBoxingConversion (null, at, pt) != null) {
  4223. score = 0;
  4224. continue;
  4225. }
  4226. } else {
  4227. score = IsArgumentCompatible (ec, a, p_mod, pt);
  4228. if (score < 0)
  4229. dynamicArgument = true;
  4230. }
  4231. }
  4232. //
  4233. // It can be applicable in expanded form (when not doing exact match like for delegates)
  4234. //
  4235. if (score != 0 && (p_mod & Parameter.Modifier.PARAMS) != 0 && (restrictions & Restrictions.CovariantDelegate) == 0) {
  4236. if (!params_expanded_form) {
  4237. pt = ((ElementTypeSpec) pt).Element;
  4238. }
  4239. if (score > 0)
  4240. score = IsArgumentCompatible (ec, a, Parameter.Modifier.NONE, pt);
  4241. if (score < 0) {
  4242. params_expanded_form = true;
  4243. dynamicArgument = true;
  4244. } else if (score == 0 || arg_count > pd.Count) {
  4245. params_expanded_form = true;
  4246. }
  4247. }
  4248. if (score > 0) {
  4249. if (params_expanded_form)
  4250. ++score;
  4251. return (arg_count - i) * 2 + score;
  4252. }
  4253. }
  4254. //
  4255. // Restore original arguments for dynamic binder to keep the intention of original source code
  4256. //
  4257. if (dynamicArgument)
  4258. arguments = orig_args;
  4259. return 0;
  4260. }
  4261. public static Expression ResolveDefaultValueArgument (ResolveContext ec, TypeSpec ptype, Expression e, Location loc)
  4262. {
  4263. if (e is Constant && e.Type == ptype)
  4264. return e;
  4265. //
  4266. // LAMESPEC: No idea what the exact rules are for System.Reflection.Missing.Value instead of null
  4267. //
  4268. if (e == EmptyExpression.MissingValue && ptype.BuiltinType == BuiltinTypeSpec.Type.Object || ptype.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
  4269. e = new MemberAccess (new MemberAccess (new MemberAccess (
  4270. new QualifiedAliasMember (QualifiedAliasMember.GlobalAlias, "System", loc), "Reflection", loc), "Missing", loc), "Value", loc);
  4271. } else if (e is Constant) {
  4272. //
  4273. // Handles int to int? conversions, DefaultParameterValue check
  4274. //
  4275. e = Convert.ImplicitConversionStandard (ec, e, ptype, loc);
  4276. if (e == null)
  4277. return null;
  4278. } else {
  4279. e = new DefaultValueExpression (new TypeExpression (ptype, loc), loc);
  4280. }
  4281. return e.Resolve (ec);
  4282. }
  4283. //
  4284. // Tests argument compatibility with the parameter
  4285. // The possible return values are
  4286. // 0 - success
  4287. // 1 - modifier mismatch
  4288. // 2 - type mismatch
  4289. // -1 - dynamic binding required
  4290. //
  4291. int IsArgumentCompatible (ResolveContext ec, Argument argument, Parameter.Modifier param_mod, TypeSpec parameter)
  4292. {
  4293. //
  4294. // Types have to be identical when ref or out modifer
  4295. // is used and argument is not of dynamic type
  4296. //
  4297. if (((argument.Modifier | param_mod) & Parameter.Modifier.RefOutMask) != 0) {
  4298. if (argument.Type != parameter) {
  4299. //
  4300. // Do full equality check after quick path
  4301. //
  4302. if (!TypeSpecComparer.IsEqual (argument.Type, parameter)) {
  4303. //
  4304. // Using dynamic for ref/out parameter can still succeed at runtime
  4305. //
  4306. if (argument.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && (argument.Modifier & Parameter.Modifier.RefOutMask) == 0 && (restrictions & Restrictions.CovariantDelegate) == 0)
  4307. return -1;
  4308. return 2;
  4309. }
  4310. }
  4311. if ((argument.Modifier & Parameter.Modifier.RefOutMask) != (param_mod & Parameter.Modifier.RefOutMask)) {
  4312. //
  4313. // Using dynamic for ref/out parameter can still succeed at runtime
  4314. //
  4315. if (argument.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && (argument.Modifier & Parameter.Modifier.RefOutMask) == 0 && (restrictions & Restrictions.CovariantDelegate) == 0)
  4316. return -1;
  4317. return 1;
  4318. }
  4319. } else {
  4320. if (argument.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && (restrictions & Restrictions.CovariantDelegate) == 0)
  4321. return -1;
  4322. //
  4323. // Use implicit conversion in all modes to return same candidates when the expression
  4324. // is used as argument or delegate conversion
  4325. //
  4326. if (!Convert.ImplicitConversionExists (ec, argument.Expr, parameter)) {
  4327. return parameter.IsDelegate && argument.Expr is AnonymousMethodExpression ? 2 : 3;
  4328. }
  4329. }
  4330. return 0;
  4331. }
  4332. static TypeSpec MoreSpecific (TypeSpec p, TypeSpec q)
  4333. {
  4334. if (TypeManager.IsGenericParameter (p) && !TypeManager.IsGenericParameter (q))
  4335. return q;
  4336. if (!TypeManager.IsGenericParameter (p) && TypeManager.IsGenericParameter (q))
  4337. return p;
  4338. var ac_p = p as ArrayContainer;
  4339. if (ac_p != null) {
  4340. var ac_q = q as ArrayContainer;
  4341. if (ac_q == null)
  4342. return null;
  4343. TypeSpec specific = MoreSpecific (ac_p.Element, ac_q.Element);
  4344. if (specific == ac_p.Element)
  4345. return p;
  4346. if (specific == ac_q.Element)
  4347. return q;
  4348. } else if (p.IsGeneric && q.IsGeneric) {
  4349. var pargs = TypeManager.GetTypeArguments (p);
  4350. var qargs = TypeManager.GetTypeArguments (q);
  4351. bool p_specific_at_least_once = false;
  4352. bool q_specific_at_least_once = false;
  4353. for (int i = 0; i < pargs.Length; i++) {
  4354. TypeSpec specific = MoreSpecific (pargs[i], qargs[i]);
  4355. if (specific == pargs[i])
  4356. p_specific_at_least_once = true;
  4357. if (specific == qargs[i])
  4358. q_specific_at_least_once = true;
  4359. }
  4360. if (p_specific_at_least_once && !q_specific_at_least_once)
  4361. return p;
  4362. if (!p_specific_at_least_once && q_specific_at_least_once)
  4363. return q;
  4364. }
  4365. return null;
  4366. }
  4367. //
  4368. // Find the best method from candidate list
  4369. //
  4370. public T ResolveMember<T> (ResolveContext rc, ref Arguments args) where T : MemberSpec, IParametersMember
  4371. {
  4372. List<AmbiguousCandidate> ambiguous_candidates = null;
  4373. MemberSpec best_candidate;
  4374. Arguments best_candidate_args = null;
  4375. bool best_candidate_params = false;
  4376. bool best_candidate_dynamic = false;
  4377. int best_candidate_rate;
  4378. IParametersMember best_parameter_member = null;
  4379. int args_count = args != null ? args.Count : 0;
  4380. Arguments candidate_args = args;
  4381. bool error_mode = false;
  4382. MemberSpec invocable_member = null;
  4383. while (true) {
  4384. best_candidate = null;
  4385. best_candidate_rate = int.MaxValue;
  4386. var type_members = members;
  4387. do {
  4388. for (int i = 0; i < type_members.Count; ++i) {
  4389. var member = type_members[i];
  4390. //
  4391. // Methods in a base class are not candidates if any method in a derived
  4392. // class is applicable
  4393. //
  4394. if ((member.Modifiers & Modifiers.OVERRIDE) != 0)
  4395. continue;
  4396. if (!error_mode) {
  4397. if (!member.IsAccessible (rc))
  4398. continue;
  4399. if (rc.IsRuntimeBinder && !member.DeclaringType.IsAccessible (rc))
  4400. continue;
  4401. if ((member.Modifiers & (Modifiers.PROTECTED | Modifiers.STATIC)) == Modifiers.PROTECTED &&
  4402. instance_qualifier != null && !instance_qualifier.CheckProtectedMemberAccess (rc, member)) {
  4403. continue;
  4404. }
  4405. }
  4406. IParametersMember pm = member as IParametersMember;
  4407. if (pm == null) {
  4408. //
  4409. // Will use it later to report ambiguity between best method and invocable member
  4410. //
  4411. if (Invocation.IsMemberInvocable (member))
  4412. invocable_member = member;
  4413. continue;
  4414. }
  4415. //
  4416. // Overload resolution is looking for base member but using parameter names
  4417. // and default values from the closest member. That means to do expensive lookup
  4418. // for the closest override for virtual or abstract members
  4419. //
  4420. if ((member.Modifiers & (Modifiers.VIRTUAL | Modifiers.ABSTRACT)) != 0) {
  4421. var override_params = base_provider.GetOverrideMemberParameters (member);
  4422. if (override_params != null)
  4423. pm = override_params;
  4424. }
  4425. //
  4426. // Check if the member candidate is applicable
  4427. //
  4428. bool params_expanded_form = false;
  4429. bool dynamic_argument = false;
  4430. TypeSpec rt = pm.MemberType;
  4431. int candidate_rate = IsApplicable (rc, ref candidate_args, args_count, ref member, pm, ref params_expanded_form, ref dynamic_argument, ref rt, error_mode);
  4432. if (lambda_conv_msgs != null)
  4433. lambda_conv_msgs.EndSession ();
  4434. //
  4435. // How does it score compare to others
  4436. //
  4437. if (candidate_rate < best_candidate_rate) {
  4438. // Fatal error (missing dependency), cannot continue
  4439. if (candidate_rate < 0)
  4440. return null;
  4441. if ((restrictions & Restrictions.GetEnumeratorLookup) != 0 && candidate_args.Count != 0) {
  4442. // Only parameterless methods are considered
  4443. } else {
  4444. best_candidate_rate = candidate_rate;
  4445. best_candidate = member;
  4446. best_candidate_args = candidate_args;
  4447. best_candidate_params = params_expanded_form;
  4448. best_candidate_dynamic = dynamic_argument;
  4449. best_parameter_member = pm;
  4450. best_candidate_return_type = rt;
  4451. }
  4452. } else if (candidate_rate == 0) {
  4453. //
  4454. // The member look is done per type for most operations but sometimes
  4455. // it's not possible like for binary operators overload because they
  4456. // are unioned between 2 sides
  4457. //
  4458. if ((restrictions & Restrictions.BaseMembersIncluded) != 0) {
  4459. if (TypeSpec.IsBaseClass (best_candidate.DeclaringType, member.DeclaringType, true))
  4460. continue;
  4461. }
  4462. bool is_better;
  4463. if (best_candidate.DeclaringType.IsInterface && member.DeclaringType.ImplementsInterface (best_candidate.DeclaringType, false)) {
  4464. //
  4465. // We pack all interface members into top level type which makes the overload resolution
  4466. // more complicated for interfaces. We compensate it by removing methods with same
  4467. // signature when building the cache hence this path should not really be hit often
  4468. //
  4469. // Example:
  4470. // interface IA { void Foo (int arg); }
  4471. // interface IB : IA { void Foo (params int[] args); }
  4472. //
  4473. // IB::Foo is the best overload when calling IB.Foo (1)
  4474. //
  4475. is_better = true;
  4476. if (ambiguous_candidates != null) {
  4477. foreach (var amb_cand in ambiguous_candidates) {
  4478. if (member.DeclaringType.ImplementsInterface (best_candidate.DeclaringType, false)) {
  4479. continue;
  4480. }
  4481. is_better = false;
  4482. break;
  4483. }
  4484. if (is_better)
  4485. ambiguous_candidates = null;
  4486. }
  4487. } else {
  4488. // Is the new candidate better
  4489. is_better = BetterFunction (rc, candidate_args, member, pm.Parameters, params_expanded_form, best_candidate, best_parameter_member.Parameters, best_candidate_params);
  4490. }
  4491. if (is_better) {
  4492. best_candidate = member;
  4493. best_candidate_args = candidate_args;
  4494. best_candidate_params = params_expanded_form;
  4495. best_candidate_dynamic = dynamic_argument;
  4496. best_parameter_member = pm;
  4497. best_candidate_return_type = rt;
  4498. } else {
  4499. // It's not better but any other found later could be but we are not sure yet
  4500. if (ambiguous_candidates == null)
  4501. ambiguous_candidates = new List<AmbiguousCandidate> ();
  4502. ambiguous_candidates.Add (new AmbiguousCandidate (member, pm.Parameters, params_expanded_form));
  4503. }
  4504. }
  4505. // Restore expanded arguments
  4506. candidate_args = args;
  4507. }
  4508. } while (best_candidate_rate != 0 && (type_members = base_provider.GetBaseMembers (type_members[0].DeclaringType.BaseType)) != null);
  4509. //
  4510. // We've found exact match
  4511. //
  4512. if (best_candidate_rate == 0)
  4513. break;
  4514. //
  4515. // Try extension methods lookup when no ordinary method match was found and provider enables it
  4516. //
  4517. if (!error_mode) {
  4518. var emg = base_provider.LookupExtensionMethod (rc);
  4519. if (emg != null) {
  4520. emg = emg.OverloadResolve (rc, ref args, null, restrictions);
  4521. if (emg != null) {
  4522. best_candidate_extension_group = emg;
  4523. return (T) (MemberSpec) emg.BestCandidate;
  4524. }
  4525. }
  4526. }
  4527. // Don't run expensive error reporting mode for probing
  4528. if (IsProbingOnly)
  4529. return null;
  4530. if (error_mode)
  4531. break;
  4532. if (lambda_conv_msgs != null && !lambda_conv_msgs.IsEmpty)
  4533. break;
  4534. lambda_conv_msgs = null;
  4535. error_mode = true;
  4536. }
  4537. //
  4538. // No best member match found, report an error
  4539. //
  4540. if (best_candidate_rate != 0 || error_mode) {
  4541. ReportOverloadError (rc, best_candidate, best_parameter_member, best_candidate_args, best_candidate_params);
  4542. return null;
  4543. }
  4544. if (best_candidate_dynamic) {
  4545. if (args[0].IsExtensionType) {
  4546. rc.Report.Error (1973, loc,
  4547. "Type `{0}' does not contain a member `{1}' and the best extension method overload `{2}' cannot be dynamically dispatched. Consider calling the method without the extension method syntax",
  4548. args [0].Type.GetSignatureForError (), best_candidate.Name, best_candidate.GetSignatureForError ());
  4549. }
  4550. //
  4551. // Check type constraints only when explicit type arguments are used
  4552. //
  4553. if (best_candidate.IsGeneric && type_arguments != null) {
  4554. MethodSpec bc = best_candidate as MethodSpec;
  4555. if (bc != null && TypeParameterSpec.HasAnyTypeParameterConstrained (bc.GenericDefinition)) {
  4556. ConstraintChecker cc = new ConstraintChecker (rc);
  4557. cc.CheckAll (bc.GetGenericMethodDefinition (), bc.TypeArguments, bc.Constraints, loc);
  4558. }
  4559. }
  4560. BestCandidateIsDynamic = true;
  4561. return null;
  4562. }
  4563. //
  4564. // These flags indicates we are running delegate probing conversion. No need to
  4565. // do more expensive checks
  4566. //
  4567. if ((restrictions & (Restrictions.ProbingOnly | Restrictions.CovariantDelegate)) == (Restrictions.CovariantDelegate | Restrictions.ProbingOnly))
  4568. return (T) best_candidate;
  4569. if (ambiguous_candidates != null) {
  4570. //
  4571. // Now check that there are no ambiguities i.e the selected method
  4572. // should be better than all the others
  4573. //
  4574. for (int ix = 0; ix < ambiguous_candidates.Count; ix++) {
  4575. var candidate = ambiguous_candidates [ix];
  4576. if (!BetterFunction (rc, best_candidate_args, best_candidate, best_parameter_member.Parameters, best_candidate_params, candidate.Member, candidate.Parameters, candidate.Expanded)) {
  4577. var ambiguous = candidate.Member;
  4578. if (custom_errors == null || !custom_errors.AmbiguousCandidates (rc, best_candidate, ambiguous)) {
  4579. rc.Report.SymbolRelatedToPreviousError (best_candidate);
  4580. rc.Report.SymbolRelatedToPreviousError (ambiguous);
  4581. rc.Report.Error (121, loc, "The call is ambiguous between the following methods or properties: `{0}' and `{1}'",
  4582. best_candidate.GetSignatureForError (), ambiguous.GetSignatureForError ());
  4583. }
  4584. return (T) best_candidate;
  4585. }
  4586. }
  4587. }
  4588. if (invocable_member != null && !IsProbingOnly) {
  4589. rc.Report.SymbolRelatedToPreviousError (best_candidate);
  4590. rc.Report.SymbolRelatedToPreviousError (invocable_member);
  4591. rc.Report.Warning (467, 2, loc, "Ambiguity between method `{0}' and invocable non-method `{1}'. Using method group",
  4592. best_candidate.GetSignatureForError (), invocable_member.GetSignatureForError ());
  4593. }
  4594. //
  4595. // And now check if the arguments are all
  4596. // compatible, perform conversions if
  4597. // necessary etc. and return if everything is
  4598. // all right
  4599. //
  4600. if (!VerifyArguments (rc, ref best_candidate_args, best_candidate, best_parameter_member, best_candidate_params))
  4601. return null;
  4602. if (best_candidate == null)
  4603. return null;
  4604. //
  4605. // Don't run possibly expensive checks in probing mode
  4606. //
  4607. if (!IsProbingOnly && !rc.IsInProbingMode) {
  4608. //
  4609. // Check ObsoleteAttribute on the best method
  4610. //
  4611. ObsoleteAttribute oa = best_candidate.GetAttributeObsolete ();
  4612. if (oa != null && !rc.IsObsolete)
  4613. AttributeTester.Report_ObsoleteMessage (oa, best_candidate.GetSignatureForError (), loc, rc.Report);
  4614. best_candidate.MemberDefinition.SetIsUsed ();
  4615. }
  4616. args = best_candidate_args;
  4617. return (T) best_candidate;
  4618. }
  4619. public MethodSpec ResolveOperator (ResolveContext rc, ref Arguments args)
  4620. {
  4621. return ResolveMember<MethodSpec> (rc, ref args);
  4622. }
  4623. void ReportArgumentMismatch (ResolveContext ec, int idx, MemberSpec method,
  4624. Argument a, AParametersCollection expected_par, TypeSpec paramType)
  4625. {
  4626. if (custom_errors != null && custom_errors.ArgumentMismatch (ec, method, a, idx))
  4627. return;
  4628. if (a.Type == InternalType.ErrorType)
  4629. return;
  4630. if (a is CollectionElementInitializer.ElementInitializerArgument) {
  4631. ec.Report.SymbolRelatedToPreviousError (method);
  4632. if ((expected_par.FixedParameters[idx].ModFlags & Parameter.Modifier.RefOutMask) != 0) {
  4633. ec.Report.Error (1954, loc, "The best overloaded collection initalizer method `{0}' cannot have `ref' or `out' modifier",
  4634. TypeManager.CSharpSignature (method));
  4635. return;
  4636. }
  4637. ec.Report.Error (1950, loc, "The best overloaded collection initalizer method `{0}' has some invalid arguments",
  4638. TypeManager.CSharpSignature (method));
  4639. } else if (IsDelegateInvoke) {
  4640. ec.Report.Error (1594, loc, "Delegate `{0}' has some invalid arguments",
  4641. DelegateType.GetSignatureForError ());
  4642. } else {
  4643. ec.Report.SymbolRelatedToPreviousError (method);
  4644. ec.Report.Error (1502, loc, "The best overloaded method match for `{0}' has some invalid arguments",
  4645. method.GetSignatureForError ());
  4646. }
  4647. Parameter.Modifier mod = idx >= expected_par.Count ? 0 : expected_par.FixedParameters[idx].ModFlags;
  4648. string index = (idx + 1).ToString ();
  4649. if (((mod & Parameter.Modifier.RefOutMask) ^ (a.Modifier & Parameter.Modifier.RefOutMask)) != 0) {
  4650. if ((mod & Parameter.Modifier.RefOutMask) == 0)
  4651. ec.Report.Error (1615, a.Expr.Location, "Argument `#{0}' does not require `{1}' modifier. Consider removing `{1}' modifier",
  4652. index, Parameter.GetModifierSignature (a.Modifier));
  4653. else
  4654. ec.Report.Error (1620, a.Expr.Location, "Argument `#{0}' is missing `{1}' modifier",
  4655. index, Parameter.GetModifierSignature (mod));
  4656. } else {
  4657. string p1 = a.GetSignatureForError ();
  4658. string p2 = paramType.GetSignatureForError ();
  4659. if (p1 == p2) {
  4660. p1 = a.Type.GetSignatureForErrorIncludingAssemblyName ();
  4661. p2 = paramType.GetSignatureForErrorIncludingAssemblyName ();
  4662. }
  4663. if ((mod & Parameter.Modifier.RefOutMask) != 0) {
  4664. p1 = Parameter.GetModifierSignature (a.Modifier) + " " + p1;
  4665. p2 = Parameter.GetModifierSignature (a.Modifier) + " " + p2;
  4666. }
  4667. ec.Report.Error (1503, a.Expr.Location,
  4668. "Argument `#{0}' cannot convert `{1}' expression to type `{2}'", index, p1, p2);
  4669. }
  4670. }
  4671. //
  4672. // We have failed to find exact match so we return error info about the closest match
  4673. //
  4674. void ReportOverloadError (ResolveContext rc, MemberSpec best_candidate, IParametersMember pm, Arguments args, bool params_expanded)
  4675. {
  4676. int ta_count = type_arguments == null ? 0 : type_arguments.Count;
  4677. int arg_count = args == null ? 0 : args.Count;
  4678. if (ta_count != best_candidate.Arity && (ta_count > 0 || ((IParametersMember) best_candidate).Parameters.IsEmpty)) {
  4679. var mg = new MethodGroupExpr (new [] { best_candidate }, best_candidate.DeclaringType, loc);
  4680. mg.Error_TypeArgumentsCannotBeUsed (rc, best_candidate, loc);
  4681. return;
  4682. }
  4683. if (lambda_conv_msgs != null && lambda_conv_msgs.Merge (rc.Report.Printer)) {
  4684. return;
  4685. }
  4686. if ((best_candidate.Modifiers & (Modifiers.PROTECTED | Modifiers.STATIC)) == Modifiers.PROTECTED &&
  4687. InstanceQualifier != null && !InstanceQualifier.CheckProtectedMemberAccess (rc, best_candidate)) {
  4688. MemberExpr.Error_ProtectedMemberAccess (rc, best_candidate, InstanceQualifier.InstanceType, loc);
  4689. }
  4690. //
  4691. // For candidates which match on parameters count report more details about incorrect arguments
  4692. //
  4693. if (pm != null) {
  4694. if (pm.Parameters.Count == arg_count || params_expanded || HasUnfilledParams (best_candidate, pm, args)) {
  4695. // Reject any inaccessible member
  4696. if (!best_candidate.IsAccessible (rc) || !best_candidate.DeclaringType.IsAccessible (rc)) {
  4697. rc.Report.SymbolRelatedToPreviousError (best_candidate);
  4698. Expression.ErrorIsInaccesible (rc, best_candidate.GetSignatureForError (), loc);
  4699. return;
  4700. }
  4701. var ms = best_candidate as MethodSpec;
  4702. if (ms != null && ms.IsGeneric) {
  4703. bool constr_ok = true;
  4704. if (ms.TypeArguments != null)
  4705. constr_ok = new ConstraintChecker (rc.MemberContext).CheckAll (ms.GetGenericMethodDefinition (), ms.TypeArguments, ms.Constraints, loc);
  4706. if (ta_count == 0 && ms.TypeArguments == null) {
  4707. if (custom_errors != null && custom_errors.TypeInferenceFailed (rc, best_candidate))
  4708. return;
  4709. if (constr_ok) {
  4710. rc.Report.Error (411, loc,
  4711. "The type arguments for method `{0}' cannot be inferred from the usage. Try specifying the type arguments explicitly",
  4712. ms.GetGenericMethodDefinition ().GetSignatureForError ());
  4713. }
  4714. return;
  4715. }
  4716. }
  4717. VerifyArguments (rc, ref args, best_candidate, pm, params_expanded);
  4718. return;
  4719. }
  4720. }
  4721. //
  4722. // We failed to find any method with correct argument count, report best candidate
  4723. //
  4724. if (custom_errors != null && custom_errors.NoArgumentMatch (rc, best_candidate))
  4725. return;
  4726. if (best_candidate.Kind == MemberKind.Constructor) {
  4727. rc.Report.SymbolRelatedToPreviousError (best_candidate);
  4728. Error_ConstructorMismatch (rc, best_candidate.DeclaringType, arg_count, loc);
  4729. } else if (IsDelegateInvoke) {
  4730. rc.Report.SymbolRelatedToPreviousError (DelegateType);
  4731. rc.Report.Error (1593, loc, "Delegate `{0}' does not take `{1}' arguments",
  4732. DelegateType.GetSignatureForError (), arg_count.ToString ());
  4733. } else {
  4734. string name = best_candidate.Kind == MemberKind.Indexer ? "this" : best_candidate.Name;
  4735. rc.Report.SymbolRelatedToPreviousError (best_candidate);
  4736. rc.Report.Error (1501, loc, "No overload for method `{0}' takes `{1}' arguments",
  4737. name, arg_count.ToString ());
  4738. }
  4739. }
  4740. static bool HasUnfilledParams (MemberSpec best_candidate, IParametersMember pm, Arguments args)
  4741. {
  4742. var p = ((IParametersMember)best_candidate).Parameters;
  4743. if (!p.HasParams)
  4744. return false;
  4745. string name = null;
  4746. for (int i = p.Count - 1; i != 0; --i) {
  4747. var fp = p.FixedParameters [i];
  4748. if ((fp.ModFlags & Parameter.Modifier.PARAMS) == 0)
  4749. continue;
  4750. name = fp.Name;
  4751. break;
  4752. }
  4753. if (args == null)
  4754. return false;
  4755. foreach (var arg in args) {
  4756. var na = arg as NamedArgument;
  4757. if (na == null)
  4758. continue;
  4759. if (na.Name == name) {
  4760. name = null;
  4761. break;
  4762. }
  4763. }
  4764. if (name == null)
  4765. return false;
  4766. return args.Count + 1 == pm.Parameters.Count;
  4767. }
  4768. bool VerifyArguments (ResolveContext ec, ref Arguments args, MemberSpec member, IParametersMember pm, bool chose_params_expanded)
  4769. {
  4770. var pd = pm.Parameters;
  4771. var cpd = ((IParametersMember) member).Parameters;
  4772. var ptypes = cpd.Types;
  4773. Parameter.Modifier p_mod = 0;
  4774. TypeSpec pt = null;
  4775. int a_idx = 0, a_pos = 0;
  4776. Argument a = null;
  4777. ArrayInitializer params_initializers = null;
  4778. bool has_unsafe_arg = pm.MemberType.IsPointer;
  4779. int arg_count = args == null ? 0 : args.Count;
  4780. for (; a_idx < arg_count; a_idx++, ++a_pos) {
  4781. a = args[a_idx];
  4782. if (a == null)
  4783. continue;
  4784. if (p_mod != Parameter.Modifier.PARAMS) {
  4785. p_mod = cpd.FixedParameters [a_idx].ModFlags;
  4786. pt = ptypes[a_idx];
  4787. has_unsafe_arg |= pt.IsPointer;
  4788. if (p_mod == Parameter.Modifier.PARAMS) {
  4789. if (chose_params_expanded) {
  4790. params_initializers = new ArrayInitializer (arg_count - a_idx, a.Expr.Location);
  4791. pt = TypeManager.GetElementType (pt);
  4792. }
  4793. }
  4794. }
  4795. //
  4796. // Types have to be identical when ref or out modifer is used
  4797. //
  4798. if (((a.Modifier | p_mod) & Parameter.Modifier.RefOutMask) != 0) {
  4799. if ((a.Modifier & Parameter.Modifier.RefOutMask) != (p_mod & Parameter.Modifier.RefOutMask))
  4800. break;
  4801. if (a.Expr.Type == pt || TypeSpecComparer.IsEqual (a.Expr.Type, pt))
  4802. continue;
  4803. break;
  4804. }
  4805. NamedArgument na = a as NamedArgument;
  4806. if (na != null) {
  4807. int name_index = pd.GetParameterIndexByName (na.Name);
  4808. if (name_index < 0 || name_index >= pd.Count) {
  4809. if (IsDelegateInvoke) {
  4810. ec.Report.SymbolRelatedToPreviousError (DelegateType);
  4811. ec.Report.Error (1746, na.Location,
  4812. "The delegate `{0}' does not contain a parameter named `{1}'",
  4813. DelegateType.GetSignatureForError (), na.Name);
  4814. } else {
  4815. ec.Report.SymbolRelatedToPreviousError (member);
  4816. ec.Report.Error (1739, na.Location,
  4817. "The best overloaded method match for `{0}' does not contain a parameter named `{1}'",
  4818. TypeManager.CSharpSignature (member), na.Name);
  4819. }
  4820. } else if (args[name_index] != a && args[name_index] != null) {
  4821. if (IsDelegateInvoke)
  4822. ec.Report.SymbolRelatedToPreviousError (DelegateType);
  4823. else
  4824. ec.Report.SymbolRelatedToPreviousError (member);
  4825. ec.Report.Error (1744, na.Location,
  4826. "Named argument `{0}' cannot be used for a parameter which has positional argument specified",
  4827. na.Name);
  4828. }
  4829. }
  4830. if (a.Expr.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
  4831. continue;
  4832. if ((restrictions & Restrictions.CovariantDelegate) != 0 && !Delegate.IsTypeCovariant (ec, a.Expr.Type, pt)) {
  4833. custom_errors.NoArgumentMatch (ec, member);
  4834. return false;
  4835. }
  4836. Expression conv;
  4837. if (a.IsExtensionType) {
  4838. if (a.Expr.Type == pt || TypeSpecComparer.IsEqual (a.Expr.Type, pt)) {
  4839. conv = a.Expr;
  4840. } else {
  4841. conv = Convert.ImplicitReferenceConversion (a.Expr, pt, false);
  4842. if (conv == null)
  4843. conv = Convert.ImplicitBoxingConversion (a.Expr, a.Expr.Type, pt);
  4844. }
  4845. } else {
  4846. conv = Convert.ImplicitConversion (ec, a.Expr, pt, loc);
  4847. }
  4848. if (conv == null)
  4849. break;
  4850. //
  4851. // Convert params arguments to an array initializer
  4852. //
  4853. if (params_initializers != null) {
  4854. // we choose to use 'a.Expr' rather than 'conv' so that
  4855. // we don't hide the kind of expression we have (esp. CompoundAssign.Helper)
  4856. params_initializers.Add (a.Expr);
  4857. args.RemoveAt (a_idx--);
  4858. --arg_count;
  4859. a.Expr = conv;
  4860. continue;
  4861. }
  4862. // Update the argument with the implicit conversion
  4863. a.Expr = conv;
  4864. }
  4865. if (a_idx != arg_count) {
  4866. ReportArgumentMismatch (ec, a_pos, member, a, pd, pt);
  4867. return false;
  4868. }
  4869. //
  4870. // Fill not provided arguments required by params modifier
  4871. //
  4872. if (params_initializers == null && arg_count + 1 == pd.Count) {
  4873. if (args == null)
  4874. args = new Arguments (1);
  4875. pt = ptypes[pd.Count - 1];
  4876. pt = TypeManager.GetElementType (pt);
  4877. has_unsafe_arg |= pt.IsPointer;
  4878. params_initializers = new ArrayInitializer (0, loc);
  4879. }
  4880. //
  4881. // Append an array argument with all params arguments
  4882. //
  4883. if (params_initializers != null) {
  4884. args.Add (new Argument (
  4885. new ArrayCreation (new TypeExpression (pt, loc), params_initializers, loc).Resolve (ec)));
  4886. arg_count++;
  4887. }
  4888. if (has_unsafe_arg && !ec.IsUnsafe) {
  4889. Expression.UnsafeError (ec, loc);
  4890. }
  4891. //
  4892. // We could infer inaccesible type arguments
  4893. //
  4894. if (type_arguments == null && member.IsGeneric) {
  4895. var ms = (MethodSpec) member;
  4896. foreach (var ta in ms.TypeArguments) {
  4897. if (!ta.IsAccessible (ec)) {
  4898. ec.Report.SymbolRelatedToPreviousError (ta);
  4899. Expression.ErrorIsInaccesible (ec, member.GetSignatureForError (), loc);
  4900. break;
  4901. }
  4902. }
  4903. }
  4904. return true;
  4905. }
  4906. }
  4907. public class ConstantExpr : MemberExpr
  4908. {
  4909. readonly ConstSpec constant;
  4910. public ConstantExpr (ConstSpec constant, Location loc)
  4911. {
  4912. this.constant = constant;
  4913. this.loc = loc;
  4914. }
  4915. public override string Name {
  4916. get { throw new NotImplementedException (); }
  4917. }
  4918. public override string KindName {
  4919. get { return "constant"; }
  4920. }
  4921. public override bool IsInstance {
  4922. get { return !IsStatic; }
  4923. }
  4924. public override bool IsStatic {
  4925. get { return true; }
  4926. }
  4927. protected override TypeSpec DeclaringType {
  4928. get { return constant.DeclaringType; }
  4929. }
  4930. public override Expression CreateExpressionTree (ResolveContext ec)
  4931. {
  4932. throw new NotSupportedException ("ET");
  4933. }
  4934. protected override Expression DoResolve (ResolveContext rc)
  4935. {
  4936. ResolveInstanceExpression (rc, null);
  4937. DoBestMemberChecks (rc, constant);
  4938. var c = constant.GetConstant (rc);
  4939. // Creates reference expression to the constant value
  4940. return Constant.CreateConstantFromValue (constant.MemberType, c.GetValue (), loc);
  4941. }
  4942. public override void Emit (EmitContext ec)
  4943. {
  4944. throw new NotSupportedException ();
  4945. }
  4946. public override string GetSignatureForError ()
  4947. {
  4948. return constant.GetSignatureForError ();
  4949. }
  4950. public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
  4951. {
  4952. Error_TypeArgumentsCannotBeUsed (ec, "constant", GetSignatureForError (), loc);
  4953. }
  4954. }
  4955. //
  4956. // Fully resolved expression that references a Field
  4957. //
  4958. public class FieldExpr : MemberExpr, IDynamicAssign, IMemoryLocation, IVariableReference
  4959. {
  4960. protected FieldSpec spec;
  4961. VariableInfo variable_info;
  4962. LocalTemporary temp;
  4963. bool prepared;
  4964. protected FieldExpr (Location l)
  4965. {
  4966. loc = l;
  4967. }
  4968. public FieldExpr (FieldSpec spec, Location loc)
  4969. {
  4970. this.spec = spec;
  4971. this.loc = loc;
  4972. type = spec.MemberType;
  4973. }
  4974. public FieldExpr (FieldBase fi, Location l)
  4975. : this (fi.Spec, l)
  4976. {
  4977. }
  4978. #region Properties
  4979. public override string Name {
  4980. get {
  4981. return spec.Name;
  4982. }
  4983. }
  4984. public bool IsHoisted {
  4985. get {
  4986. IVariableReference hv = InstanceExpression as IVariableReference;
  4987. return hv != null && hv.IsHoisted;
  4988. }
  4989. }
  4990. public override bool IsInstance {
  4991. get {
  4992. return !spec.IsStatic;
  4993. }
  4994. }
  4995. public override bool IsStatic {
  4996. get {
  4997. return spec.IsStatic;
  4998. }
  4999. }
  5000. public override string KindName {
  5001. get { return "field"; }
  5002. }
  5003. public FieldSpec Spec {
  5004. get {
  5005. return spec;
  5006. }
  5007. }
  5008. protected override TypeSpec DeclaringType {
  5009. get {
  5010. return spec.DeclaringType;
  5011. }
  5012. }
  5013. public VariableInfo VariableInfo {
  5014. get {
  5015. return variable_info;
  5016. }
  5017. }
  5018. #endregion
  5019. public override string GetSignatureForError ()
  5020. {
  5021. return spec.GetSignatureForError ();
  5022. }
  5023. public bool IsMarshalByRefAccess (ResolveContext rc)
  5024. {
  5025. // Checks possible ldflda of field access expression
  5026. return !spec.IsStatic && TypeSpec.IsValueType (spec.MemberType) && !(InstanceExpression is This) &&
  5027. rc.Module.PredefinedTypes.MarshalByRefObject.Define () &&
  5028. TypeSpec.IsBaseClass (spec.DeclaringType, rc.Module.PredefinedTypes.MarshalByRefObject.TypeSpec, false);
  5029. }
  5030. public void SetHasAddressTaken ()
  5031. {
  5032. IVariableReference vr = InstanceExpression as IVariableReference;
  5033. if (vr != null) {
  5034. vr.SetHasAddressTaken ();
  5035. }
  5036. }
  5037. protected override void CloneTo (CloneContext clonectx, Expression target)
  5038. {
  5039. var t = (FieldExpr) target;
  5040. if (InstanceExpression != null)
  5041. t.InstanceExpression = InstanceExpression.Clone (clonectx);
  5042. }
  5043. public override Expression CreateExpressionTree (ResolveContext ec)
  5044. {
  5045. if (ConditionalAccess) {
  5046. Error_NullShortCircuitInsideExpressionTree (ec);
  5047. }
  5048. return CreateExpressionTree (ec, true);
  5049. }
  5050. public Expression CreateExpressionTree (ResolveContext ec, bool convertInstance)
  5051. {
  5052. Arguments args;
  5053. Expression instance;
  5054. if (InstanceExpression == null) {
  5055. instance = new NullLiteral (loc);
  5056. } else if (convertInstance) {
  5057. instance = InstanceExpression.CreateExpressionTree (ec);
  5058. } else {
  5059. args = new Arguments (1);
  5060. args.Add (new Argument (InstanceExpression));
  5061. instance = CreateExpressionFactoryCall (ec, "Constant", args);
  5062. }
  5063. args = Arguments.CreateForExpressionTree (ec, null,
  5064. instance,
  5065. CreateTypeOfExpression ());
  5066. return CreateExpressionFactoryCall (ec, "Field", args);
  5067. }
  5068. public Expression CreateTypeOfExpression ()
  5069. {
  5070. return new TypeOfField (spec, loc);
  5071. }
  5072. protected override Expression DoResolve (ResolveContext ec)
  5073. {
  5074. spec.MemberDefinition.SetIsUsed ();
  5075. return DoResolve (ec, null);
  5076. }
  5077. Expression DoResolve (ResolveContext ec, Expression rhs)
  5078. {
  5079. bool lvalue_instance = rhs != null && IsInstance && spec.DeclaringType.IsStruct;
  5080. if (rhs != this) {
  5081. ResolveConditionalAccessReceiver (ec);
  5082. if (ResolveInstanceExpression (ec, rhs)) {
  5083. // Resolve the field's instance expression while flow analysis is turned
  5084. // off: when accessing a field "a.b", we must check whether the field
  5085. // "a.b" is initialized, not whether the whole struct "a" is initialized.
  5086. if (lvalue_instance) {
  5087. bool out_access = rhs == EmptyExpression.OutAccess || rhs == EmptyExpression.LValueMemberOutAccess;
  5088. Expression right_side =
  5089. out_access ? EmptyExpression.LValueMemberOutAccess : EmptyExpression.LValueMemberAccess;
  5090. InstanceExpression = InstanceExpression.ResolveLValue (ec, right_side);
  5091. } else {
  5092. InstanceExpression = InstanceExpression.Resolve (ec, ResolveFlags.VariableOrValue);
  5093. }
  5094. if (InstanceExpression == null)
  5095. return null;
  5096. }
  5097. DoBestMemberChecks (ec, spec);
  5098. if (conditional_access_receiver)
  5099. ec.With (ResolveContext.Options.ConditionalAccessReceiver, false);
  5100. }
  5101. var fb = spec as FixedFieldSpec;
  5102. IVariableReference var = InstanceExpression as IVariableReference;
  5103. if (fb != null) {
  5104. IFixedExpression fe = InstanceExpression as IFixedExpression;
  5105. if (!ec.HasSet (ResolveContext.Options.FixedInitializerScope) && (fe == null || !fe.IsFixed)) {
  5106. ec.Report.Error (1666, loc, "You cannot use fixed size buffers contained in unfixed expressions. Try using the fixed statement");
  5107. }
  5108. if (InstanceExpression.eclass != ExprClass.Variable) {
  5109. ec.Report.SymbolRelatedToPreviousError (spec);
  5110. ec.Report.Error (1708, loc, "`{0}': Fixed size buffers can only be accessed through locals or fields",
  5111. TypeManager.GetFullNameSignature (spec));
  5112. } else if (var != null && var.IsHoisted) {
  5113. AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, var, loc);
  5114. }
  5115. return new FixedBufferPtr (this, fb.ElementType, loc).Resolve (ec);
  5116. }
  5117. //
  5118. // Set flow-analysis variable info for struct member access. It will be check later
  5119. // for precise error reporting
  5120. //
  5121. if (var != null && var.VariableInfo != null && InstanceExpression.Type.IsStruct) {
  5122. variable_info = var.VariableInfo.GetStructFieldInfo (Name);
  5123. }
  5124. if (ConditionalAccess) {
  5125. if (conditional_access_receiver)
  5126. type = LiftMemberType (ec, type);
  5127. if (InstanceExpression.IsNull)
  5128. return Constant.CreateConstantFromValue (type, null, loc);
  5129. }
  5130. eclass = ExprClass.Variable;
  5131. return this;
  5132. }
  5133. public void SetFieldAssigned (FlowAnalysisContext fc)
  5134. {
  5135. if (!IsInstance)
  5136. return;
  5137. bool lvalue_instance = spec.DeclaringType.IsStruct;
  5138. if (lvalue_instance) {
  5139. var var = InstanceExpression as IVariableReference;
  5140. if (var != null && var.VariableInfo != null) {
  5141. fc.SetStructFieldAssigned (var.VariableInfo, Name);
  5142. }
  5143. }
  5144. var fe = InstanceExpression as FieldExpr;
  5145. if (fe != null) {
  5146. Expression instance;
  5147. do {
  5148. instance = fe.InstanceExpression;
  5149. var fe_instance = instance as FieldExpr;
  5150. if ((fe_instance != null && !fe_instance.IsStatic) || instance is LocalVariableReference) {
  5151. if (TypeSpec.IsReferenceType (fe.Type) && instance.Type.IsStruct) {
  5152. var var = InstanceExpression as IVariableReference;
  5153. if (var != null && var.VariableInfo == null) {
  5154. var var_inst = instance as IVariableReference;
  5155. if (var_inst == null || (var_inst.VariableInfo != null && !fc.IsDefinitelyAssigned (var_inst.VariableInfo)))
  5156. fc.Report.Warning (1060, 1, fe.loc, "Use of possibly unassigned field `{0}'", fe.Name);
  5157. }
  5158. }
  5159. if (fe_instance != null) {
  5160. fe = fe_instance;
  5161. continue;
  5162. }
  5163. }
  5164. break;
  5165. } while (true);
  5166. if (instance != null && TypeSpec.IsReferenceType (instance.Type))
  5167. instance.FlowAnalysis (fc);
  5168. } else {
  5169. if (TypeSpec.IsReferenceType (InstanceExpression.Type))
  5170. InstanceExpression.FlowAnalysis (fc);
  5171. }
  5172. }
  5173. Expression Error_AssignToReadonly (ResolveContext rc, Expression right_side)
  5174. {
  5175. // The return value is always null. Returning a value simplifies calling code.
  5176. if (right_side == EmptyExpression.OutAccess) {
  5177. if (IsStatic) {
  5178. rc.Report.Error (199, loc, "A static readonly field `{0}' cannot be passed ref or out (except in a static constructor)",
  5179. GetSignatureForError ());
  5180. } else {
  5181. rc.Report.Error (192, loc, "A readonly field `{0}' cannot be passed ref or out (except in a constructor)",
  5182. GetSignatureForError ());
  5183. }
  5184. return null;
  5185. }
  5186. if (right_side == EmptyExpression.LValueMemberAccess) {
  5187. // Already reported as CS1648/CS1650
  5188. return null;
  5189. }
  5190. if (right_side == EmptyExpression.LValueMemberOutAccess) {
  5191. if (IsStatic) {
  5192. rc.Report.Error (1651, loc, "Fields of static readonly field `{0}' cannot be passed ref or out (except in a static constructor)",
  5193. GetSignatureForError ());
  5194. } else {
  5195. rc.Report.Error (1649, loc, "Members of readonly field `{0}' cannot be passed ref or out (except in a constructor)",
  5196. GetSignatureForError ());
  5197. }
  5198. return null;
  5199. }
  5200. if (IsStatic) {
  5201. rc.Report.Error (198, loc, "A static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
  5202. GetSignatureForError ());
  5203. } else {
  5204. rc.Report.Error (191, loc, "A readonly field `{0}' cannot be assigned to (except in a constructor or a variable initializer)",
  5205. GetSignatureForError ());
  5206. }
  5207. return null;
  5208. }
  5209. public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
  5210. {
  5211. if (ConditionalAccess)
  5212. throw new NotSupportedException ("null propagating operator assignment");
  5213. if (spec is FixedFieldSpec) {
  5214. // It could be much better error message but we want to be error compatible
  5215. Error_ValueAssignment (ec, right_side);
  5216. }
  5217. Expression e = DoResolve (ec, right_side);
  5218. if (e == null)
  5219. return null;
  5220. spec.MemberDefinition.SetIsAssigned ();
  5221. if ((right_side == EmptyExpression.UnaryAddress || right_side == EmptyExpression.OutAccess) &&
  5222. (spec.Modifiers & Modifiers.VOLATILE) != 0) {
  5223. ec.Report.Warning (420, 1, loc,
  5224. "`{0}': A volatile field references will not be treated as volatile",
  5225. spec.GetSignatureForError ());
  5226. }
  5227. if (spec.IsReadOnly) {
  5228. // InitOnly fields can only be assigned in constructors or initializers
  5229. if (!ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.ConstructorScope))
  5230. return Error_AssignToReadonly (ec, right_side);
  5231. if (ec.HasSet (ResolveContext.Options.ConstructorScope)) {
  5232. // InitOnly fields cannot be assigned-to in a different constructor from their declaring type
  5233. if (ec.CurrentMemberDefinition.Parent.PartialContainer.Definition != spec.DeclaringType.GetDefinition ())
  5234. return Error_AssignToReadonly (ec, right_side);
  5235. // static InitOnly fields cannot be assigned-to in an instance constructor
  5236. if (IsStatic && !ec.IsStatic)
  5237. return Error_AssignToReadonly (ec, right_side);
  5238. // instance constructors can't modify InitOnly fields of other instances of the same type
  5239. if (!IsStatic && !(InstanceExpression is This))
  5240. return Error_AssignToReadonly (ec, right_side);
  5241. }
  5242. }
  5243. if (right_side == EmptyExpression.OutAccess && IsMarshalByRefAccess (ec)) {
  5244. ec.Report.SymbolRelatedToPreviousError (spec.DeclaringType);
  5245. ec.Report.Warning (197, 1, loc,
  5246. "Passing `{0}' as ref or out or taking its address may cause a runtime exception because it is a field of a marshal-by-reference class",
  5247. GetSignatureForError ());
  5248. }
  5249. eclass = ExprClass.Variable;
  5250. return this;
  5251. }
  5252. public override void FlowAnalysis (FlowAnalysisContext fc)
  5253. {
  5254. var var = InstanceExpression as IVariableReference;
  5255. if (var != null) {
  5256. var vi = var.VariableInfo;
  5257. if (vi != null && !fc.IsStructFieldDefinitelyAssigned (vi, Name)) {
  5258. fc.Report.Error (170, loc, "Use of possibly unassigned field `{0}'", Name);
  5259. return;
  5260. }
  5261. if (TypeSpec.IsValueType (InstanceExpression.Type) && InstanceExpression is VariableReference)
  5262. return;
  5263. }
  5264. base.FlowAnalysis (fc);
  5265. if (conditional_access_receiver)
  5266. fc.ConditionalAccessEnd ();
  5267. }
  5268. public override int GetHashCode ()
  5269. {
  5270. return spec.GetHashCode ();
  5271. }
  5272. public bool IsFixed {
  5273. get {
  5274. //
  5275. // A variable of the form V.I is fixed when V is a fixed variable of a struct type
  5276. //
  5277. IVariableReference variable = InstanceExpression as IVariableReference;
  5278. if (variable != null)
  5279. return InstanceExpression.Type.IsStruct && variable.IsFixed;
  5280. IFixedExpression fe = InstanceExpression as IFixedExpression;
  5281. return fe != null && fe.IsFixed;
  5282. }
  5283. }
  5284. public override bool Equals (object obj)
  5285. {
  5286. FieldExpr fe = obj as FieldExpr;
  5287. if (fe == null)
  5288. return false;
  5289. if (spec != fe.spec)
  5290. return false;
  5291. if (InstanceExpression == null || fe.InstanceExpression == null)
  5292. return true;
  5293. return InstanceExpression.Equals (fe.InstanceExpression);
  5294. }
  5295. public void Emit (EmitContext ec, bool leave_copy)
  5296. {
  5297. bool is_volatile = (spec.Modifiers & Modifiers.VOLATILE) != 0;
  5298. if (IsStatic){
  5299. if (is_volatile)
  5300. ec.Emit (OpCodes.Volatile);
  5301. ec.Emit (OpCodes.Ldsfld, spec);
  5302. } else {
  5303. if (!prepared) {
  5304. if (conditional_access_receiver)
  5305. ec.ConditionalAccess = new ConditionalAccessContext (type, ec.DefineLabel ());
  5306. EmitInstance (ec, false);
  5307. }
  5308. // Optimization for build-in types
  5309. if (type.IsStruct && type == ec.CurrentType && InstanceExpression.Type == type) {
  5310. ec.EmitLoadFromPtr (type);
  5311. } else {
  5312. var ff = spec as FixedFieldSpec;
  5313. if (ff != null) {
  5314. ec.Emit (OpCodes.Ldflda, spec);
  5315. ec.Emit (OpCodes.Ldflda, ff.Element);
  5316. } else {
  5317. if (is_volatile)
  5318. ec.Emit (OpCodes.Volatile);
  5319. ec.Emit (OpCodes.Ldfld, spec);
  5320. }
  5321. }
  5322. if (conditional_access_receiver) {
  5323. ec.CloseConditionalAccess (type.IsNullableType && type != spec.MemberType ? type : null);
  5324. }
  5325. }
  5326. if (leave_copy) {
  5327. ec.Emit (OpCodes.Dup);
  5328. if (!IsStatic) {
  5329. temp = new LocalTemporary (this.Type);
  5330. temp.Store (ec);
  5331. }
  5332. }
  5333. }
  5334. public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
  5335. {
  5336. bool has_await_source = ec.HasSet (BuilderContext.Options.AsyncBody) && source.ContainsEmitWithAwait ();
  5337. if (isCompound && !(source is DynamicExpressionStatement) && !has_await_source) {
  5338. prepared = true;
  5339. }
  5340. if (IsInstance) {
  5341. if (ConditionalAccess)
  5342. throw new NotImplementedException ("null operator assignment");
  5343. if (has_await_source)
  5344. source = source.EmitToField (ec);
  5345. EmitInstance (ec, prepared);
  5346. }
  5347. source.Emit (ec);
  5348. if (leave_copy || ec.NotifyEvaluatorOnStore) {
  5349. ec.Emit (OpCodes.Dup);
  5350. if (!IsStatic) {
  5351. temp = new LocalTemporary (this.Type);
  5352. temp.Store (ec);
  5353. }
  5354. }
  5355. if ((spec.Modifiers & Modifiers.VOLATILE) != 0)
  5356. ec.Emit (OpCodes.Volatile);
  5357. spec.MemberDefinition.SetIsAssigned ();
  5358. if (IsStatic)
  5359. ec.Emit (OpCodes.Stsfld, spec);
  5360. else
  5361. ec.Emit (OpCodes.Stfld, spec);
  5362. if (ec.NotifyEvaluatorOnStore) {
  5363. if (!IsStatic)
  5364. throw new NotImplementedException ("instance field write");
  5365. if (leave_copy)
  5366. ec.Emit (OpCodes.Dup);
  5367. ec.Module.Evaluator.EmitValueChangedCallback (ec, Name, type, loc);
  5368. }
  5369. if (temp != null) {
  5370. temp.Emit (ec);
  5371. temp.Release (ec);
  5372. temp = null;
  5373. }
  5374. }
  5375. //
  5376. // Emits store to field with prepared values on stack
  5377. //
  5378. public void EmitAssignFromStack (EmitContext ec)
  5379. {
  5380. if (IsStatic) {
  5381. ec.Emit (OpCodes.Stsfld, spec);
  5382. } else {
  5383. ec.Emit (OpCodes.Stfld, spec);
  5384. }
  5385. }
  5386. public override void Emit (EmitContext ec)
  5387. {
  5388. Emit (ec, false);
  5389. }
  5390. public override void EmitSideEffect (EmitContext ec)
  5391. {
  5392. bool is_volatile = (spec.Modifiers & Modifiers.VOLATILE) != 0;
  5393. if (is_volatile) // || is_marshal_by_ref ())
  5394. base.EmitSideEffect (ec);
  5395. }
  5396. public virtual void AddressOf (EmitContext ec, AddressOp mode)
  5397. {
  5398. if ((mode & AddressOp.Store) != 0)
  5399. spec.MemberDefinition.SetIsAssigned ();
  5400. if ((mode & AddressOp.Load) != 0)
  5401. spec.MemberDefinition.SetIsUsed ();
  5402. //
  5403. // Handle initonly fields specially: make a copy and then
  5404. // get the address of the copy.
  5405. //
  5406. bool need_copy;
  5407. if (spec.IsReadOnly){
  5408. need_copy = true;
  5409. if (ec.HasSet (EmitContext.Options.ConstructorScope) && spec.DeclaringType == ec.CurrentType) {
  5410. if (IsStatic){
  5411. if (ec.IsStatic)
  5412. need_copy = false;
  5413. } else
  5414. need_copy = false;
  5415. }
  5416. } else
  5417. need_copy = false;
  5418. if (need_copy) {
  5419. Emit (ec);
  5420. var temp = ec.GetTemporaryLocal (type);
  5421. ec.Emit (OpCodes.Stloc, temp);
  5422. ec.Emit (OpCodes.Ldloca, temp);
  5423. return;
  5424. }
  5425. if (IsStatic){
  5426. ec.Emit (OpCodes.Ldsflda, spec);
  5427. } else {
  5428. if (!prepared)
  5429. EmitInstance (ec, false);
  5430. ec.Emit (OpCodes.Ldflda, spec);
  5431. }
  5432. }
  5433. public SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
  5434. {
  5435. return MakeExpression (ctx);
  5436. }
  5437. public override SLE.Expression MakeExpression (BuilderContext ctx)
  5438. {
  5439. #if STATIC
  5440. return base.MakeExpression (ctx);
  5441. #else
  5442. return SLE.Expression.Field (
  5443. IsStatic ? null : InstanceExpression.MakeExpression (ctx),
  5444. spec.GetMetaInfo ());
  5445. #endif
  5446. }
  5447. public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
  5448. {
  5449. Error_TypeArgumentsCannotBeUsed (ec, "field", GetSignatureForError (), loc);
  5450. }
  5451. }
  5452. //
  5453. // Expression that evaluates to a Property.
  5454. //
  5455. // This is not an LValue because we need to re-write the expression. We
  5456. // can not take data from the stack and store it.
  5457. //
  5458. sealed class PropertyExpr : PropertyOrIndexerExpr<PropertySpec>
  5459. {
  5460. Arguments arguments;
  5461. public PropertyExpr (PropertySpec spec, Location l)
  5462. : base (l)
  5463. {
  5464. best_candidate = spec;
  5465. type = spec.MemberType;
  5466. }
  5467. #region Properties
  5468. protected override Arguments Arguments {
  5469. get {
  5470. return arguments;
  5471. }
  5472. set {
  5473. arguments = value;
  5474. }
  5475. }
  5476. protected override TypeSpec DeclaringType {
  5477. get {
  5478. return best_candidate.DeclaringType;
  5479. }
  5480. }
  5481. public override string Name {
  5482. get {
  5483. return best_candidate.Name;
  5484. }
  5485. }
  5486. public override bool IsInstance {
  5487. get {
  5488. return !IsStatic;
  5489. }
  5490. }
  5491. public override bool IsStatic {
  5492. get {
  5493. return best_candidate.IsStatic;
  5494. }
  5495. }
  5496. public override string KindName {
  5497. get { return "property"; }
  5498. }
  5499. public PropertySpec PropertyInfo {
  5500. get {
  5501. return best_candidate;
  5502. }
  5503. }
  5504. #endregion
  5505. public override MethodGroupExpr CanReduceLambda (AnonymousMethodBody body)
  5506. {
  5507. if (best_candidate == null || !(best_candidate.IsStatic || InstanceExpression is This))
  5508. return null;
  5509. var args_count = arguments == null ? 0 : arguments.Count;
  5510. if (args_count != body.Parameters.Count && args_count == 0)
  5511. return null;
  5512. var mg = MethodGroupExpr.CreatePredefined (best_candidate.Get, DeclaringType, loc);
  5513. mg.InstanceExpression = InstanceExpression;
  5514. return mg;
  5515. }
  5516. public static PropertyExpr CreatePredefined (PropertySpec spec, Location loc)
  5517. {
  5518. return new PropertyExpr (spec, loc) {
  5519. Getter = spec.Get,
  5520. Setter = spec.Set
  5521. };
  5522. }
  5523. public override Expression CreateExpressionTree (ResolveContext ec)
  5524. {
  5525. if (ConditionalAccess) {
  5526. Error_NullShortCircuitInsideExpressionTree (ec);
  5527. }
  5528. Arguments args;
  5529. if (IsSingleDimensionalArrayLength ()) {
  5530. args = new Arguments (1);
  5531. args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
  5532. return CreateExpressionFactoryCall (ec, "ArrayLength", args);
  5533. }
  5534. args = new Arguments (2);
  5535. if (InstanceExpression == null)
  5536. args.Add (new Argument (new NullLiteral (loc)));
  5537. else
  5538. args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
  5539. args.Add (new Argument (new TypeOfMethod (Getter, loc)));
  5540. return CreateExpressionFactoryCall (ec, "Property", args);
  5541. }
  5542. public Expression CreateSetterTypeOfExpression (ResolveContext rc)
  5543. {
  5544. DoResolveLValue (rc, null);
  5545. return new TypeOfMethod (Setter, loc);
  5546. }
  5547. public override string GetSignatureForError ()
  5548. {
  5549. return best_candidate.GetSignatureForError ();
  5550. }
  5551. public override SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
  5552. {
  5553. #if STATIC
  5554. return base.MakeExpression (ctx);
  5555. #else
  5556. return SLE.Expression.Property (InstanceExpression.MakeExpression (ctx), (MethodInfo) Setter.GetMetaInfo ());
  5557. #endif
  5558. }
  5559. public override SLE.Expression MakeExpression (BuilderContext ctx)
  5560. {
  5561. #if STATIC
  5562. return base.MakeExpression (ctx);
  5563. #else
  5564. return SLE.Expression.Property (InstanceExpression.MakeExpression (ctx), (MethodInfo) Getter.GetMetaInfo ());
  5565. #endif
  5566. }
  5567. void Error_PropertyNotValid (ResolveContext ec)
  5568. {
  5569. ec.Report.SymbolRelatedToPreviousError (best_candidate);
  5570. ec.Report.Error (1546, loc, "Property or event `{0}' is not supported by the C# language",
  5571. GetSignatureForError ());
  5572. }
  5573. bool IsSingleDimensionalArrayLength ()
  5574. {
  5575. if (best_candidate.DeclaringType.BuiltinType != BuiltinTypeSpec.Type.Array || !best_candidate.HasGet || Name != "Length")
  5576. return false;
  5577. ArrayContainer ac = InstanceExpression.Type as ArrayContainer;
  5578. return ac != null && ac.Rank == 1;
  5579. }
  5580. public override void Emit (EmitContext ec, bool leave_copy)
  5581. {
  5582. //
  5583. // Special case: length of single dimension array property is turned into ldlen
  5584. //
  5585. if (IsSingleDimensionalArrayLength ()) {
  5586. if (conditional_access_receiver) {
  5587. ec.ConditionalAccess = new ConditionalAccessContext (type, ec.DefineLabel ());
  5588. }
  5589. EmitInstance (ec, false);
  5590. ec.Emit (OpCodes.Ldlen);
  5591. ec.Emit (OpCodes.Conv_I4);
  5592. if (conditional_access_receiver) {
  5593. ec.CloseConditionalAccess (type);
  5594. }
  5595. return;
  5596. }
  5597. base.Emit (ec, leave_copy);
  5598. }
  5599. public override void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
  5600. {
  5601. Arguments args;
  5602. LocalTemporary await_source_arg = null;
  5603. if (isCompound && !(source is DynamicExpressionStatement)) {
  5604. emitting_compound_assignment = true;
  5605. source.Emit (ec);
  5606. if (has_await_arguments) {
  5607. await_source_arg = new LocalTemporary (Type);
  5608. await_source_arg.Store (ec);
  5609. args = new Arguments (1);
  5610. args.Add (new Argument (await_source_arg));
  5611. if (leave_copy) {
  5612. temp = await_source_arg;
  5613. }
  5614. has_await_arguments = false;
  5615. } else {
  5616. args = null;
  5617. if (leave_copy) {
  5618. ec.Emit (OpCodes.Dup);
  5619. temp = new LocalTemporary (this.Type);
  5620. temp.Store (ec);
  5621. }
  5622. }
  5623. } else {
  5624. args = arguments ?? new Arguments (1);
  5625. if (leave_copy) {
  5626. source.Emit (ec);
  5627. temp = new LocalTemporary (this.Type);
  5628. temp.Store (ec);
  5629. args.Add (new Argument (temp));
  5630. } else {
  5631. args.Add (new Argument (source));
  5632. }
  5633. }
  5634. emitting_compound_assignment = false;
  5635. var call = new CallEmitter ();
  5636. call.InstanceExpression = InstanceExpression;
  5637. if (args == null)
  5638. call.InstanceExpressionOnStack = true;
  5639. if (ConditionalAccess) {
  5640. call.ConditionalAccess = true;
  5641. }
  5642. if (leave_copy)
  5643. call.Emit (ec, Setter, args, loc);
  5644. else
  5645. call.EmitStatement (ec, Setter, args, loc);
  5646. if (temp != null) {
  5647. temp.Emit (ec);
  5648. temp.Release (ec);
  5649. }
  5650. if (await_source_arg != null) {
  5651. await_source_arg.Release (ec);
  5652. }
  5653. }
  5654. public override void FlowAnalysis (FlowAnalysisContext fc)
  5655. {
  5656. base.FlowAnalysis (fc);
  5657. if (conditional_access_receiver)
  5658. fc.ConditionalAccessEnd ();
  5659. }
  5660. protected override Expression OverloadResolve (ResolveContext rc, Expression right_side)
  5661. {
  5662. eclass = ExprClass.PropertyAccess;
  5663. if (best_candidate.IsNotCSharpCompatible) {
  5664. Error_PropertyNotValid (rc);
  5665. }
  5666. ResolveInstanceExpression (rc, right_side);
  5667. if ((best_candidate.Modifiers & (Modifiers.ABSTRACT | Modifiers.VIRTUAL)) != 0 && best_candidate.DeclaringType != InstanceExpression.Type) {
  5668. var filter = new MemberFilter (best_candidate.Name, 0, MemberKind.Property, null, null);
  5669. var p = MemberCache.FindMember (InstanceExpression.Type, filter, BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as PropertySpec;
  5670. if (p != null) {
  5671. type = p.MemberType;
  5672. }
  5673. }
  5674. DoBestMemberChecks (rc, best_candidate);
  5675. // Handling of com-imported properties with any number of default property parameters
  5676. if (best_candidate.HasGet && !best_candidate.Get.Parameters.IsEmpty) {
  5677. var p = best_candidate.Get.Parameters;
  5678. arguments = new Arguments (p.Count);
  5679. for (int i = 0; i < p.Count; ++i) {
  5680. arguments.Add (new Argument (OverloadResolver.ResolveDefaultValueArgument (rc, p.Types [i], p.FixedParameters [i].DefaultValue, loc)));
  5681. }
  5682. } else if (best_candidate.HasSet && best_candidate.Set.Parameters.Count > 1) {
  5683. var p = best_candidate.Set.Parameters;
  5684. arguments = new Arguments (p.Count - 1);
  5685. for (int i = 0; i < p.Count - 1; ++i) {
  5686. arguments.Add (new Argument (OverloadResolver.ResolveDefaultValueArgument (rc, p.Types [i], p.FixedParameters [i].DefaultValue, loc)));
  5687. }
  5688. }
  5689. return this;
  5690. }
  5691. public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
  5692. {
  5693. Error_TypeArgumentsCannotBeUsed (ec, "property", GetSignatureForError (), loc);
  5694. }
  5695. }
  5696. abstract class PropertyOrIndexerExpr<T> : MemberExpr, IDynamicAssign where T : PropertySpec
  5697. {
  5698. // getter and setter can be different for base calls
  5699. MethodSpec getter, setter;
  5700. protected T best_candidate;
  5701. protected LocalTemporary temp;
  5702. protected bool emitting_compound_assignment;
  5703. protected bool has_await_arguments;
  5704. protected PropertyOrIndexerExpr (Location l)
  5705. {
  5706. loc = l;
  5707. }
  5708. #region Properties
  5709. protected abstract Arguments Arguments { get; set; }
  5710. public MethodSpec Getter {
  5711. get {
  5712. return getter;
  5713. }
  5714. set {
  5715. getter = value;
  5716. }
  5717. }
  5718. public MethodSpec Setter {
  5719. get {
  5720. return setter;
  5721. }
  5722. set {
  5723. setter = value;
  5724. }
  5725. }
  5726. #endregion
  5727. protected override Expression DoResolve (ResolveContext ec)
  5728. {
  5729. if (eclass == ExprClass.Unresolved) {
  5730. ResolveConditionalAccessReceiver (ec);
  5731. var expr = OverloadResolve (ec, null);
  5732. if (expr == null)
  5733. return null;
  5734. if (expr != this)
  5735. return expr.Resolve (ec);
  5736. if (conditional_access_receiver) {
  5737. type = LiftMemberType (ec, type);
  5738. ec.With (ResolveContext.Options.ConditionalAccessReceiver, false);
  5739. }
  5740. }
  5741. if (!ResolveGetter (ec))
  5742. return null;
  5743. return this;
  5744. }
  5745. public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
  5746. {
  5747. if (ConditionalAccess)
  5748. throw new NotSupportedException ("null propagating operator assignment");
  5749. if (right_side == EmptyExpression.OutAccess) {
  5750. // TODO: best_candidate can be null at this point
  5751. INamedBlockVariable variable = null;
  5752. if (best_candidate != null && ec.CurrentBlock.ParametersBlock.TopBlock.GetLocalName (best_candidate.Name, ec.CurrentBlock, ref variable) && variable is Linq.RangeVariable) {
  5753. ec.Report.Error (1939, loc, "A range variable `{0}' may not be passes as `ref' or `out' parameter",
  5754. best_candidate.Name);
  5755. } else {
  5756. right_side.DoResolveLValue (ec, this);
  5757. }
  5758. return null;
  5759. }
  5760. if (eclass == ExprClass.Unresolved) {
  5761. var expr = OverloadResolve (ec, right_side);
  5762. if (expr == null)
  5763. return null;
  5764. if (expr != this)
  5765. return expr.ResolveLValue (ec, right_side);
  5766. } else {
  5767. ResolveInstanceExpression (ec, right_side);
  5768. }
  5769. if (!ResolveSetter (ec))
  5770. return null;
  5771. return this;
  5772. }
  5773. void EmitConditionalAccess (EmitContext ec, ref CallEmitter call, MethodSpec method, Arguments arguments)
  5774. {
  5775. ec.ConditionalAccess = new ConditionalAccessContext (type, ec.DefineLabel ());
  5776. call.Emit (ec, method, arguments, loc);
  5777. ec.CloseConditionalAccess (method.ReturnType != type && type.IsNullableType ? type : null);
  5778. }
  5779. //
  5780. // Implements the IAssignMethod interface for assignments
  5781. //
  5782. public virtual void Emit (EmitContext ec, bool leave_copy)
  5783. {
  5784. var call = new CallEmitter ();
  5785. call.ConditionalAccess = ConditionalAccess;
  5786. call.InstanceExpression = InstanceExpression;
  5787. if (has_await_arguments)
  5788. call.HasAwaitArguments = true;
  5789. else
  5790. call.DuplicateArguments = emitting_compound_assignment;
  5791. if (conditional_access_receiver)
  5792. EmitConditionalAccess (ec, ref call, Getter, Arguments);
  5793. else
  5794. call.Emit (ec, Getter, Arguments, loc);
  5795. if (call.HasAwaitArguments) {
  5796. InstanceExpression = call.InstanceExpression;
  5797. Arguments = call.EmittedArguments;
  5798. has_await_arguments = true;
  5799. }
  5800. if (leave_copy) {
  5801. ec.Emit (OpCodes.Dup);
  5802. temp = new LocalTemporary (Type);
  5803. temp.Store (ec);
  5804. }
  5805. }
  5806. public abstract void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound);
  5807. public override void Emit (EmitContext ec)
  5808. {
  5809. Emit (ec, false);
  5810. }
  5811. protected override FieldExpr EmitToFieldSource (EmitContext ec)
  5812. {
  5813. has_await_arguments = true;
  5814. Emit (ec, false);
  5815. return null;
  5816. }
  5817. public abstract SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source);
  5818. protected abstract Expression OverloadResolve (ResolveContext rc, Expression right_side);
  5819. bool ResolveGetter (ResolveContext rc)
  5820. {
  5821. if (!best_candidate.HasGet) {
  5822. if (InstanceExpression != EmptyExpression.Null) {
  5823. rc.Report.SymbolRelatedToPreviousError (best_candidate);
  5824. rc.Report.Error (154, loc, "The property or indexer `{0}' cannot be used in this context because it lacks the `get' accessor",
  5825. best_candidate.GetSignatureForError ());
  5826. return false;
  5827. }
  5828. } else if (!best_candidate.Get.IsAccessible (rc) || !best_candidate.Get.DeclaringType.IsAccessible (rc)) {
  5829. if (best_candidate.HasDifferentAccessibility) {
  5830. rc.Report.SymbolRelatedToPreviousError (best_candidate.Get);
  5831. rc.Report.Error (271, loc, "The property or indexer `{0}' cannot be used in this context because the get accessor is inaccessible",
  5832. TypeManager.CSharpSignature (best_candidate));
  5833. } else {
  5834. rc.Report.SymbolRelatedToPreviousError (best_candidate.Get);
  5835. ErrorIsInaccesible (rc, best_candidate.Get.GetSignatureForError (), loc);
  5836. }
  5837. }
  5838. if (best_candidate.HasDifferentAccessibility) {
  5839. CheckProtectedMemberAccess (rc, best_candidate.Get);
  5840. }
  5841. getter = CandidateToBaseOverride (rc, best_candidate.Get);
  5842. return true;
  5843. }
  5844. bool ResolveSetter (ResolveContext rc)
  5845. {
  5846. if (!best_candidate.HasSet) {
  5847. rc.Report.Error (200, loc, "Property or indexer `{0}' cannot be assigned to (it is read-only)",
  5848. GetSignatureForError ());
  5849. return false;
  5850. }
  5851. if (!best_candidate.Set.IsAccessible (rc) || !best_candidate.Set.DeclaringType.IsAccessible (rc)) {
  5852. if (best_candidate.HasDifferentAccessibility) {
  5853. rc.Report.SymbolRelatedToPreviousError (best_candidate.Set);
  5854. rc.Report.Error (272, loc, "The property or indexer `{0}' cannot be used in this context because the set accessor is inaccessible",
  5855. GetSignatureForError ());
  5856. } else {
  5857. rc.Report.SymbolRelatedToPreviousError (best_candidate.Set);
  5858. ErrorIsInaccesible (rc, best_candidate.GetSignatureForError (), loc);
  5859. }
  5860. }
  5861. if (best_candidate.HasDifferentAccessibility)
  5862. CheckProtectedMemberAccess (rc, best_candidate.Set);
  5863. setter = CandidateToBaseOverride (rc, best_candidate.Set);
  5864. return true;
  5865. }
  5866. }
  5867. /// <summary>
  5868. /// Fully resolved expression that evaluates to an Event
  5869. /// </summary>
  5870. public class EventExpr : MemberExpr, IAssignMethod
  5871. {
  5872. readonly EventSpec spec;
  5873. MethodSpec op;
  5874. public EventExpr (EventSpec spec, Location loc)
  5875. {
  5876. this.spec = spec;
  5877. this.loc = loc;
  5878. }
  5879. #region Properties
  5880. protected override TypeSpec DeclaringType {
  5881. get {
  5882. return spec.DeclaringType;
  5883. }
  5884. }
  5885. public override string Name {
  5886. get {
  5887. return spec.Name;
  5888. }
  5889. }
  5890. public override bool IsInstance {
  5891. get {
  5892. return !spec.IsStatic;
  5893. }
  5894. }
  5895. public override bool IsStatic {
  5896. get {
  5897. return spec.IsStatic;
  5898. }
  5899. }
  5900. public override string KindName {
  5901. get { return "event"; }
  5902. }
  5903. public MethodSpec Operator {
  5904. get {
  5905. return op;
  5906. }
  5907. }
  5908. #endregion
  5909. public override MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
  5910. {
  5911. //
  5912. // If the event is local to this class and we are not lhs of +=/-= we transform ourselves into a FieldExpr
  5913. //
  5914. if (!ec.HasSet (ResolveContext.Options.CompoundAssignmentScope)) {
  5915. if (spec.BackingField != null &&
  5916. (spec.DeclaringType == ec.CurrentType || TypeManager.IsNestedChildOf (ec.CurrentType, spec.DeclaringType.MemberDefinition))) {
  5917. spec.MemberDefinition.SetIsUsed ();
  5918. if (!ec.IsObsolete) {
  5919. ObsoleteAttribute oa = spec.GetAttributeObsolete ();
  5920. if (oa != null)
  5921. AttributeTester.Report_ObsoleteMessage (oa, spec.GetSignatureForError (), loc, ec.Report);
  5922. }
  5923. if ((spec.Modifiers & (Modifiers.ABSTRACT | Modifiers.EXTERN)) != 0)
  5924. Error_AssignmentEventOnly (ec);
  5925. FieldExpr ml = new FieldExpr (spec.BackingField, loc);
  5926. InstanceExpression = null;
  5927. return ml.ResolveMemberAccess (ec, left, original);
  5928. }
  5929. }
  5930. return base.ResolveMemberAccess (ec, left, original);
  5931. }
  5932. public override Expression CreateExpressionTree (ResolveContext ec)
  5933. {
  5934. throw new NotSupportedException ("ET");
  5935. }
  5936. public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
  5937. {
  5938. if (right_side == EmptyExpression.EventAddition) {
  5939. op = spec.AccessorAdd;
  5940. } else if (right_side == EmptyExpression.EventSubtraction) {
  5941. op = spec.AccessorRemove;
  5942. }
  5943. if (op == null) {
  5944. Error_AssignmentEventOnly (ec);
  5945. return null;
  5946. }
  5947. op = CandidateToBaseOverride (ec, op);
  5948. return this;
  5949. }
  5950. protected override Expression DoResolve (ResolveContext ec)
  5951. {
  5952. eclass = ExprClass.EventAccess;
  5953. type = spec.MemberType;
  5954. ResolveInstanceExpression (ec, null);
  5955. if (!ec.HasSet (ResolveContext.Options.CompoundAssignmentScope)) {
  5956. Error_AssignmentEventOnly (ec);
  5957. }
  5958. DoBestMemberChecks (ec, spec);
  5959. return this;
  5960. }
  5961. public override void Emit (EmitContext ec)
  5962. {
  5963. throw new NotSupportedException ();
  5964. //Error_CannotAssign ();
  5965. }
  5966. #region IAssignMethod Members
  5967. public void Emit (EmitContext ec, bool leave_copy)
  5968. {
  5969. throw new NotImplementedException ();
  5970. }
  5971. public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
  5972. {
  5973. if (leave_copy || !isCompound)
  5974. throw new NotImplementedException ("EventExpr::EmitAssign");
  5975. Arguments args = new Arguments (1);
  5976. args.Add (new Argument (source));
  5977. // TODO: Wrong, needs receiver
  5978. // if (NullShortCircuit) {
  5979. // ec.ConditionalAccess = new ConditionalAccessContext (type, ec.DefineLabel ());
  5980. // }
  5981. var call = new CallEmitter ();
  5982. call.InstanceExpression = InstanceExpression;
  5983. call.ConditionalAccess = ConditionalAccess;
  5984. call.EmitStatement (ec, op, args, loc);
  5985. // if (NullShortCircuit)
  5986. // ec.CloseConditionalAccess (null);
  5987. }
  5988. #endregion
  5989. void Error_AssignmentEventOnly (ResolveContext ec)
  5990. {
  5991. if (spec.DeclaringType == ec.CurrentType || TypeManager.IsNestedChildOf (ec.CurrentType, spec.DeclaringType.MemberDefinition)) {
  5992. ec.Report.Error (79, loc,
  5993. "The event `{0}' can only appear on the left hand side of `+=' or `-=' operator",
  5994. GetSignatureForError ());
  5995. } else {
  5996. ec.Report.Error (70, loc,
  5997. "The event `{0}' can only appear on the left hand side of += or -= when used outside of the type `{1}'",
  5998. GetSignatureForError (), spec.DeclaringType.GetSignatureForError ());
  5999. }
  6000. }
  6001. protected override void Error_CannotCallAbstractBase (ResolveContext rc, string name)
  6002. {
  6003. name = name.Substring (0, name.LastIndexOf ('.'));
  6004. base.Error_CannotCallAbstractBase (rc, name);
  6005. }
  6006. public override string GetSignatureForError ()
  6007. {
  6008. return TypeManager.CSharpSignature (spec);
  6009. }
  6010. public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
  6011. {
  6012. Error_TypeArgumentsCannotBeUsed (ec, "event", GetSignatureForError (), loc);
  6013. }
  6014. }
  6015. public class TemporaryVariableReference : VariableReference
  6016. {
  6017. public class Declarator : Statement
  6018. {
  6019. TemporaryVariableReference variable;
  6020. public Declarator (TemporaryVariableReference variable)
  6021. {
  6022. this.variable = variable;
  6023. loc = variable.loc;
  6024. }
  6025. protected override void DoEmit (EmitContext ec)
  6026. {
  6027. variable.li.CreateBuilder (ec);
  6028. }
  6029. public override void Emit (EmitContext ec)
  6030. {
  6031. // Don't create sequence point
  6032. DoEmit (ec);
  6033. }
  6034. protected override bool DoFlowAnalysis (FlowAnalysisContext fc)
  6035. {
  6036. return false;
  6037. }
  6038. protected override void CloneTo (CloneContext clonectx, Statement target)
  6039. {
  6040. // Nothing
  6041. }
  6042. }
  6043. LocalVariable li;
  6044. public TemporaryVariableReference (LocalVariable li, Location loc)
  6045. {
  6046. this.li = li;
  6047. this.type = li.Type;
  6048. this.loc = loc;
  6049. }
  6050. public override bool IsLockedByStatement {
  6051. get {
  6052. return false;
  6053. }
  6054. set {
  6055. }
  6056. }
  6057. public LocalVariable LocalInfo {
  6058. get {
  6059. return li;
  6060. }
  6061. }
  6062. public static TemporaryVariableReference Create (TypeSpec type, Block block, Location loc)
  6063. {
  6064. var li = LocalVariable.CreateCompilerGenerated (type, block, loc);
  6065. return new TemporaryVariableReference (li, loc);
  6066. }
  6067. protected override Expression DoResolve (ResolveContext ec)
  6068. {
  6069. eclass = ExprClass.Variable;
  6070. //
  6071. // Don't capture temporary variables except when using
  6072. // state machine redirection and block yields
  6073. //
  6074. if (ec.CurrentAnonymousMethod is StateMachineInitializer &&
  6075. (ec.CurrentBlock.Explicit.HasYield || ec.CurrentBlock.Explicit.HasAwait) &&
  6076. ec.IsVariableCapturingRequired) {
  6077. AnonymousMethodStorey storey = li.Block.Explicit.CreateAnonymousMethodStorey (ec);
  6078. storey.CaptureLocalVariable (ec, li);
  6079. }
  6080. return this;
  6081. }
  6082. public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
  6083. {
  6084. return Resolve (ec);
  6085. }
  6086. public override void Emit (EmitContext ec)
  6087. {
  6088. li.CreateBuilder (ec);
  6089. Emit (ec, false);
  6090. }
  6091. public void EmitAssign (EmitContext ec, Expression source)
  6092. {
  6093. li.CreateBuilder (ec);
  6094. EmitAssign (ec, source, false, false);
  6095. }
  6096. public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
  6097. {
  6098. return li.HoistedVariant;
  6099. }
  6100. public override bool IsFixed {
  6101. get { return true; }
  6102. }
  6103. public override bool IsRef {
  6104. get { return false; }
  6105. }
  6106. public override string Name {
  6107. get { throw new NotImplementedException (); }
  6108. }
  6109. public override void SetHasAddressTaken ()
  6110. {
  6111. throw new NotImplementedException ();
  6112. }
  6113. protected override ILocalVariable Variable {
  6114. get { return li; }
  6115. }
  6116. public override VariableInfo VariableInfo {
  6117. get { return null; }
  6118. }
  6119. }
  6120. ///
  6121. /// Handles `var' contextual keyword; var becomes a keyword only
  6122. /// if no type called var exists in a variable scope
  6123. ///
  6124. class VarExpr : SimpleName
  6125. {
  6126. public VarExpr (Location loc)
  6127. : base ("var", loc)
  6128. {
  6129. }
  6130. public bool InferType (ResolveContext ec, Expression right_side)
  6131. {
  6132. if (type != null)
  6133. throw new InternalErrorException ("An implicitly typed local variable could not be redefined");
  6134. type = right_side.Type;
  6135. if (type == InternalType.NullLiteral || type.Kind == MemberKind.Void || type == InternalType.AnonymousMethod || type == InternalType.MethodGroup) {
  6136. ec.Report.Error (815, loc,
  6137. "An implicitly typed local variable declaration cannot be initialized with `{0}'",
  6138. type.GetSignatureForError ());
  6139. return false;
  6140. }
  6141. eclass = ExprClass.Variable;
  6142. return true;
  6143. }
  6144. protected override void Error_TypeOrNamespaceNotFound (IMemberContext ec)
  6145. {
  6146. if (ec.Module.Compiler.Settings.Version < LanguageVersion.V_3)
  6147. base.Error_TypeOrNamespaceNotFound (ec);
  6148. else
  6149. ec.Module.Compiler.Report.Error (825, loc, "The contextual keyword `var' may only appear within a local variable declaration");
  6150. }
  6151. }
  6152. public class InvalidStatementExpression : Statement
  6153. {
  6154. public Expression Expression {
  6155. get;
  6156. private set;
  6157. }
  6158. public InvalidStatementExpression (Expression expr)
  6159. {
  6160. this.Expression = expr;
  6161. }
  6162. public override void Emit (EmitContext ec)
  6163. {
  6164. // nothing
  6165. }
  6166. protected override void DoEmit (EmitContext ec)
  6167. {
  6168. // nothing
  6169. }
  6170. protected override void CloneTo (CloneContext clonectx, Statement target)
  6171. {
  6172. // nothing
  6173. }
  6174. public override Mono.CSharp.Expression CreateExpressionTree (ResolveContext ec)
  6175. {
  6176. return null;
  6177. }
  6178. public override object Accept (Mono.CSharp.StructuralVisitor visitor)
  6179. {
  6180. return visitor.Visit (this);
  6181. }
  6182. protected override bool DoFlowAnalysis(FlowAnalysisContext fc)
  6183. {
  6184. return false;
  6185. }
  6186. }
  6187. }