/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

Large files are truncated click here to view the full file

  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.ImplicitStandardConve