PageRenderTime 56ms CodeModel.GetById 11ms RepoModel.GetById 0ms app.codeStats 1ms

/mcs/mcs/statement.cs

https://bitbucket.org/danipen/mono
C# | 6461 lines | 4695 code | 1203 blank | 563 comment | 1052 complexity | d1889fc01f02f011c13a627ec1b68019 MD5 | raw file
Possible License(s): Unlicense, Apache-2.0, LGPL-2.0, MPL-2.0-no-copyleft-exception, CC-BY-SA-3.0, GPL-2.0

Large files files are truncated, but you can click here to view the full file

  1. //
  2. // statement.cs: Statement representation for the IL tree.
  3. //
  4. // Authors:
  5. // Miguel de Icaza (miguel@ximian.com)
  6. // Martin Baulig (martin@ximian.com)
  7. // Marek Safar (marek.safar@gmail.com)
  8. //
  9. // Copyright 2001, 2002, 2003 Ximian, Inc.
  10. // Copyright 2003, 2004 Novell, Inc.
  11. // Copyright 2011 Xamarin Inc.
  12. //
  13. using System;
  14. using System.Collections.Generic;
  15. #if STATIC
  16. using IKVM.Reflection.Emit;
  17. #else
  18. using System.Reflection.Emit;
  19. #endif
  20. namespace Mono.CSharp {
  21. public abstract class Statement {
  22. public Location loc;
  23. /// <summary>
  24. /// Resolves the statement, true means that all sub-statements
  25. /// did resolve ok.
  26. // </summary>
  27. public virtual bool Resolve (BlockContext bc)
  28. {
  29. return true;
  30. }
  31. /// <summary>
  32. /// We already know that the statement is unreachable, but we still
  33. /// need to resolve it to catch errors.
  34. /// </summary>
  35. public virtual bool ResolveUnreachable (BlockContext ec, bool warn)
  36. {
  37. //
  38. // This conflicts with csc's way of doing this, but IMHO it's
  39. // the right thing to do.
  40. //
  41. // If something is unreachable, we still check whether it's
  42. // correct. This means that you cannot use unassigned variables
  43. // in unreachable code, for instance.
  44. //
  45. bool unreachable = false;
  46. if (warn && !ec.UnreachableReported) {
  47. ec.UnreachableReported = true;
  48. unreachable = true;
  49. ec.Report.Warning (162, 2, loc, "Unreachable code detected");
  50. }
  51. ec.StartFlowBranching (FlowBranching.BranchingType.Block, loc);
  52. bool ok = Resolve (ec);
  53. ec.KillFlowBranching ();
  54. if (unreachable) {
  55. ec.UnreachableReported = false;
  56. }
  57. return ok;
  58. }
  59. /// <summary>
  60. /// Return value indicates whether all code paths emitted return.
  61. /// </summary>
  62. protected abstract void DoEmit (EmitContext ec);
  63. public virtual void Emit (EmitContext ec)
  64. {
  65. ec.Mark (loc);
  66. DoEmit (ec);
  67. if (ec.StatementEpilogue != null) {
  68. ec.EmitEpilogue ();
  69. }
  70. }
  71. //
  72. // This routine must be overrided in derived classes and make copies
  73. // of all the data that might be modified if resolved
  74. //
  75. protected abstract void CloneTo (CloneContext clonectx, Statement target);
  76. public Statement Clone (CloneContext clonectx)
  77. {
  78. Statement s = (Statement) this.MemberwiseClone ();
  79. CloneTo (clonectx, s);
  80. return s;
  81. }
  82. public virtual Expression CreateExpressionTree (ResolveContext ec)
  83. {
  84. ec.Report.Error (834, loc, "A lambda expression with statement body cannot be converted to an expresion tree");
  85. return null;
  86. }
  87. public virtual object Accept (StructuralVisitor visitor)
  88. {
  89. return visitor.Visit (this);
  90. }
  91. }
  92. public sealed class EmptyStatement : Statement
  93. {
  94. public EmptyStatement (Location loc)
  95. {
  96. this.loc = loc;
  97. }
  98. public override bool Resolve (BlockContext ec)
  99. {
  100. return true;
  101. }
  102. public override bool ResolveUnreachable (BlockContext ec, bool warn)
  103. {
  104. return true;
  105. }
  106. public override void Emit (EmitContext ec)
  107. {
  108. }
  109. protected override void DoEmit (EmitContext ec)
  110. {
  111. throw new NotSupportedException ();
  112. }
  113. protected override void CloneTo (CloneContext clonectx, Statement target)
  114. {
  115. // nothing needed.
  116. }
  117. public override object Accept (StructuralVisitor visitor)
  118. {
  119. return visitor.Visit (this);
  120. }
  121. }
  122. public class If : Statement {
  123. Expression expr;
  124. public Statement TrueStatement;
  125. public Statement FalseStatement;
  126. bool is_true_ret;
  127. public If (Expression bool_expr, Statement true_statement, Location l)
  128. : this (bool_expr, true_statement, null, l)
  129. {
  130. }
  131. public If (Expression bool_expr,
  132. Statement true_statement,
  133. Statement false_statement,
  134. Location l)
  135. {
  136. this.expr = bool_expr;
  137. TrueStatement = true_statement;
  138. FalseStatement = false_statement;
  139. loc = l;
  140. }
  141. public Expression Expr {
  142. get {
  143. return this.expr;
  144. }
  145. }
  146. public override bool Resolve (BlockContext ec)
  147. {
  148. bool ok = true;
  149. expr = expr.Resolve (ec);
  150. if (expr == null) {
  151. ok = false;
  152. } else {
  153. //
  154. // Dead code elimination
  155. //
  156. if (expr is Constant) {
  157. bool take = !((Constant) expr).IsDefaultValue;
  158. if (take) {
  159. if (!TrueStatement.Resolve (ec))
  160. return false;
  161. if ((FalseStatement != null) &&
  162. !FalseStatement.ResolveUnreachable (ec, true))
  163. return false;
  164. FalseStatement = null;
  165. } else {
  166. if (!TrueStatement.ResolveUnreachable (ec, true))
  167. return false;
  168. TrueStatement = null;
  169. if ((FalseStatement != null) &&
  170. !FalseStatement.Resolve (ec))
  171. return false;
  172. }
  173. return true;
  174. }
  175. }
  176. ec.StartFlowBranching (FlowBranching.BranchingType.Conditional, loc);
  177. ok &= TrueStatement.Resolve (ec);
  178. is_true_ret = ec.CurrentBranching.CurrentUsageVector.IsUnreachable;
  179. ec.CurrentBranching.CreateSibling ();
  180. if (FalseStatement != null)
  181. ok &= FalseStatement.Resolve (ec);
  182. ec.EndFlowBranching ();
  183. return ok;
  184. }
  185. protected override void DoEmit (EmitContext ec)
  186. {
  187. Label false_target = ec.DefineLabel ();
  188. Label end;
  189. //
  190. // If we're a boolean constant, Resolve() already
  191. // eliminated dead code for us.
  192. //
  193. Constant c = expr as Constant;
  194. if (c != null){
  195. c.EmitSideEffect (ec);
  196. if (!c.IsDefaultValue)
  197. TrueStatement.Emit (ec);
  198. else if (FalseStatement != null)
  199. FalseStatement.Emit (ec);
  200. return;
  201. }
  202. expr.EmitBranchable (ec, false_target, false);
  203. TrueStatement.Emit (ec);
  204. if (FalseStatement != null){
  205. bool branch_emitted = false;
  206. end = ec.DefineLabel ();
  207. if (!is_true_ret){
  208. ec.Emit (OpCodes.Br, end);
  209. branch_emitted = true;
  210. }
  211. ec.MarkLabel (false_target);
  212. FalseStatement.Emit (ec);
  213. if (branch_emitted)
  214. ec.MarkLabel (end);
  215. } else {
  216. ec.MarkLabel (false_target);
  217. }
  218. }
  219. protected override void CloneTo (CloneContext clonectx, Statement t)
  220. {
  221. If target = (If) t;
  222. target.expr = expr.Clone (clonectx);
  223. target.TrueStatement = TrueStatement.Clone (clonectx);
  224. if (FalseStatement != null)
  225. target.FalseStatement = FalseStatement.Clone (clonectx);
  226. }
  227. public override object Accept (StructuralVisitor visitor)
  228. {
  229. return visitor.Visit (this);
  230. }
  231. }
  232. public class Do : Statement {
  233. public Expression expr;
  234. public Statement EmbeddedStatement;
  235. public Do (Statement statement, BooleanExpression bool_expr, Location doLocation, Location whileLocation)
  236. {
  237. expr = bool_expr;
  238. EmbeddedStatement = statement;
  239. loc = doLocation;
  240. WhileLocation = whileLocation;
  241. }
  242. public Location WhileLocation {
  243. get; private set;
  244. }
  245. public override bool Resolve (BlockContext ec)
  246. {
  247. bool ok = true;
  248. ec.StartFlowBranching (FlowBranching.BranchingType.Loop, loc);
  249. bool was_unreachable = ec.CurrentBranching.CurrentUsageVector.IsUnreachable;
  250. ec.StartFlowBranching (FlowBranching.BranchingType.Embedded, loc);
  251. if (!EmbeddedStatement.Resolve (ec))
  252. ok = false;
  253. ec.EndFlowBranching ();
  254. if (ec.CurrentBranching.CurrentUsageVector.IsUnreachable && !was_unreachable)
  255. ec.Report.Warning (162, 2, expr.Location, "Unreachable code detected");
  256. expr = expr.Resolve (ec);
  257. if (expr == null)
  258. ok = false;
  259. else if (expr is Constant){
  260. bool infinite = !((Constant) expr).IsDefaultValue;
  261. if (infinite)
  262. ec.CurrentBranching.CurrentUsageVector.Goto ();
  263. }
  264. ec.EndFlowBranching ();
  265. return ok;
  266. }
  267. protected override void DoEmit (EmitContext ec)
  268. {
  269. Label loop = ec.DefineLabel ();
  270. Label old_begin = ec.LoopBegin;
  271. Label old_end = ec.LoopEnd;
  272. ec.LoopBegin = ec.DefineLabel ();
  273. ec.LoopEnd = ec.DefineLabel ();
  274. ec.MarkLabel (loop);
  275. EmbeddedStatement.Emit (ec);
  276. ec.MarkLabel (ec.LoopBegin);
  277. // Mark start of while condition
  278. ec.Mark (WhileLocation);
  279. //
  280. // Dead code elimination
  281. //
  282. if (expr is Constant) {
  283. bool res = !((Constant) expr).IsDefaultValue;
  284. expr.EmitSideEffect (ec);
  285. if (res)
  286. ec.Emit (OpCodes.Br, loop);
  287. } else {
  288. expr.EmitBranchable (ec, loop, true);
  289. }
  290. ec.MarkLabel (ec.LoopEnd);
  291. ec.LoopBegin = old_begin;
  292. ec.LoopEnd = old_end;
  293. }
  294. protected override void CloneTo (CloneContext clonectx, Statement t)
  295. {
  296. Do target = (Do) t;
  297. target.EmbeddedStatement = EmbeddedStatement.Clone (clonectx);
  298. target.expr = expr.Clone (clonectx);
  299. }
  300. public override object Accept (StructuralVisitor visitor)
  301. {
  302. return visitor.Visit (this);
  303. }
  304. }
  305. public class While : Statement {
  306. public Expression expr;
  307. public Statement Statement;
  308. bool infinite, empty;
  309. public While (BooleanExpression bool_expr, Statement statement, Location l)
  310. {
  311. this.expr = bool_expr;
  312. Statement = statement;
  313. loc = l;
  314. }
  315. public override bool Resolve (BlockContext ec)
  316. {
  317. bool ok = true;
  318. expr = expr.Resolve (ec);
  319. if (expr == null)
  320. ok = false;
  321. //
  322. // Inform whether we are infinite or not
  323. //
  324. if (expr is Constant){
  325. bool value = !((Constant) expr).IsDefaultValue;
  326. if (value == false){
  327. if (!Statement.ResolveUnreachable (ec, true))
  328. return false;
  329. empty = true;
  330. return true;
  331. } else
  332. infinite = true;
  333. }
  334. ec.StartFlowBranching (FlowBranching.BranchingType.Loop, loc);
  335. if (!infinite)
  336. ec.CurrentBranching.CreateSibling ();
  337. ec.StartFlowBranching (FlowBranching.BranchingType.Embedded, loc);
  338. if (!Statement.Resolve (ec))
  339. ok = false;
  340. ec.EndFlowBranching ();
  341. // There's no direct control flow from the end of the embedded statement to the end of the loop
  342. ec.CurrentBranching.CurrentUsageVector.Goto ();
  343. ec.EndFlowBranching ();
  344. return ok;
  345. }
  346. protected override void DoEmit (EmitContext ec)
  347. {
  348. if (empty) {
  349. expr.EmitSideEffect (ec);
  350. return;
  351. }
  352. Label old_begin = ec.LoopBegin;
  353. Label old_end = ec.LoopEnd;
  354. ec.LoopBegin = ec.DefineLabel ();
  355. ec.LoopEnd = ec.DefineLabel ();
  356. //
  357. // Inform whether we are infinite or not
  358. //
  359. if (expr is Constant) {
  360. // expr is 'true', since the 'empty' case above handles the 'false' case
  361. ec.MarkLabel (ec.LoopBegin);
  362. if (ec.EmitAccurateDebugInfo)
  363. ec.Emit (OpCodes.Nop);
  364. expr.EmitSideEffect (ec);
  365. Statement.Emit (ec);
  366. ec.Emit (OpCodes.Br, ec.LoopBegin);
  367. //
  368. // Inform that we are infinite (ie, `we return'), only
  369. // if we do not `break' inside the code.
  370. //
  371. ec.MarkLabel (ec.LoopEnd);
  372. } else {
  373. Label while_loop = ec.DefineLabel ();
  374. ec.Emit (OpCodes.Br, ec.LoopBegin);
  375. ec.MarkLabel (while_loop);
  376. Statement.Emit (ec);
  377. ec.MarkLabel (ec.LoopBegin);
  378. ec.Mark (loc);
  379. expr.EmitBranchable (ec, while_loop, true);
  380. ec.MarkLabel (ec.LoopEnd);
  381. }
  382. ec.LoopBegin = old_begin;
  383. ec.LoopEnd = old_end;
  384. }
  385. protected override void CloneTo (CloneContext clonectx, Statement t)
  386. {
  387. While target = (While) t;
  388. target.expr = expr.Clone (clonectx);
  389. target.Statement = Statement.Clone (clonectx);
  390. }
  391. public override object Accept (StructuralVisitor visitor)
  392. {
  393. return visitor.Visit (this);
  394. }
  395. }
  396. public class For : Statement
  397. {
  398. bool infinite, empty;
  399. public For (Location l)
  400. {
  401. loc = l;
  402. }
  403. public Statement Initializer {
  404. get; set;
  405. }
  406. public Expression Condition {
  407. get; set;
  408. }
  409. public Statement Iterator {
  410. get; set;
  411. }
  412. public Statement Statement {
  413. get; set;
  414. }
  415. public override bool Resolve (BlockContext ec)
  416. {
  417. bool ok = true;
  418. if (Initializer != null) {
  419. if (!Initializer.Resolve (ec))
  420. ok = false;
  421. }
  422. if (Condition != null) {
  423. Condition = Condition.Resolve (ec);
  424. if (Condition == null)
  425. ok = false;
  426. else if (Condition is Constant) {
  427. bool value = !((Constant) Condition).IsDefaultValue;
  428. if (value == false){
  429. if (!Statement.ResolveUnreachable (ec, true))
  430. return false;
  431. if ((Iterator != null) &&
  432. !Iterator.ResolveUnreachable (ec, false))
  433. return false;
  434. empty = true;
  435. return true;
  436. } else
  437. infinite = true;
  438. }
  439. } else
  440. infinite = true;
  441. ec.StartFlowBranching (FlowBranching.BranchingType.Loop, loc);
  442. if (!infinite)
  443. ec.CurrentBranching.CreateSibling ();
  444. bool was_unreachable = ec.CurrentBranching.CurrentUsageVector.IsUnreachable;
  445. ec.StartFlowBranching (FlowBranching.BranchingType.Embedded, loc);
  446. if (!Statement.Resolve (ec))
  447. ok = false;
  448. ec.EndFlowBranching ();
  449. if (Iterator != null){
  450. if (ec.CurrentBranching.CurrentUsageVector.IsUnreachable) {
  451. if (!Iterator.ResolveUnreachable (ec, !was_unreachable))
  452. ok = false;
  453. } else {
  454. if (!Iterator.Resolve (ec))
  455. ok = false;
  456. }
  457. }
  458. // There's no direct control flow from the end of the embedded statement to the end of the loop
  459. ec.CurrentBranching.CurrentUsageVector.Goto ();
  460. ec.EndFlowBranching ();
  461. return ok;
  462. }
  463. protected override void DoEmit (EmitContext ec)
  464. {
  465. if (Initializer != null)
  466. Initializer.Emit (ec);
  467. if (empty) {
  468. Condition.EmitSideEffect (ec);
  469. return;
  470. }
  471. Label old_begin = ec.LoopBegin;
  472. Label old_end = ec.LoopEnd;
  473. Label loop = ec.DefineLabel ();
  474. Label test = ec.DefineLabel ();
  475. ec.LoopBegin = ec.DefineLabel ();
  476. ec.LoopEnd = ec.DefineLabel ();
  477. ec.Emit (OpCodes.Br, test);
  478. ec.MarkLabel (loop);
  479. Statement.Emit (ec);
  480. ec.MarkLabel (ec.LoopBegin);
  481. Iterator.Emit (ec);
  482. ec.MarkLabel (test);
  483. //
  484. // If test is null, there is no test, and we are just
  485. // an infinite loop
  486. //
  487. if (Condition != null) {
  488. ec.Mark (Condition.Location);
  489. //
  490. // The Resolve code already catches the case for
  491. // Test == Constant (false) so we know that
  492. // this is true
  493. //
  494. if (Condition is Constant) {
  495. Condition.EmitSideEffect (ec);
  496. ec.Emit (OpCodes.Br, loop);
  497. } else {
  498. Condition.EmitBranchable (ec, loop, true);
  499. }
  500. } else
  501. ec.Emit (OpCodes.Br, loop);
  502. ec.MarkLabel (ec.LoopEnd);
  503. ec.LoopBegin = old_begin;
  504. ec.LoopEnd = old_end;
  505. }
  506. protected override void CloneTo (CloneContext clonectx, Statement t)
  507. {
  508. For target = (For) t;
  509. if (Initializer != null)
  510. target.Initializer = Initializer.Clone (clonectx);
  511. if (Condition != null)
  512. target.Condition = Condition.Clone (clonectx);
  513. if (Iterator != null)
  514. target.Iterator = Iterator.Clone (clonectx);
  515. target.Statement = Statement.Clone (clonectx);
  516. }
  517. public override object Accept (StructuralVisitor visitor)
  518. {
  519. return visitor.Visit (this);
  520. }
  521. }
  522. public class StatementExpression : Statement
  523. {
  524. ExpressionStatement expr;
  525. public StatementExpression (ExpressionStatement expr)
  526. {
  527. this.expr = expr;
  528. loc = expr.Location;
  529. }
  530. public StatementExpression (ExpressionStatement expr, Location loc)
  531. {
  532. this.expr = expr;
  533. this.loc = loc;
  534. }
  535. public ExpressionStatement Expr {
  536. get {
  537. return this.expr;
  538. }
  539. }
  540. protected override void CloneTo (CloneContext clonectx, Statement t)
  541. {
  542. StatementExpression target = (StatementExpression) t;
  543. target.expr = (ExpressionStatement) expr.Clone (clonectx);
  544. }
  545. protected override void DoEmit (EmitContext ec)
  546. {
  547. expr.EmitStatement (ec);
  548. }
  549. public override bool Resolve (BlockContext ec)
  550. {
  551. expr = expr.ResolveStatement (ec);
  552. return expr != null;
  553. }
  554. public override object Accept (StructuralVisitor visitor)
  555. {
  556. return visitor.Visit (this);
  557. }
  558. }
  559. public class StatementErrorExpression : Statement
  560. {
  561. readonly Expression expr;
  562. public StatementErrorExpression (Expression expr)
  563. {
  564. this.expr = expr;
  565. }
  566. public Expression Expr {
  567. get {
  568. return expr;
  569. }
  570. }
  571. protected override void DoEmit (EmitContext ec)
  572. {
  573. throw new NotSupportedException ();
  574. }
  575. protected override void CloneTo (CloneContext clonectx, Statement target)
  576. {
  577. throw new NotImplementedException ();
  578. }
  579. public override object Accept (StructuralVisitor visitor)
  580. {
  581. return visitor.Visit (this);
  582. }
  583. }
  584. //
  585. // Simple version of statement list not requiring a block
  586. //
  587. public class StatementList : Statement
  588. {
  589. List<Statement> statements;
  590. public StatementList (Statement first, Statement second)
  591. {
  592. statements = new List<Statement> () { first, second };
  593. }
  594. #region Properties
  595. public IList<Statement> Statements {
  596. get {
  597. return statements;
  598. }
  599. }
  600. #endregion
  601. public void Add (Statement statement)
  602. {
  603. statements.Add (statement);
  604. }
  605. public override bool Resolve (BlockContext ec)
  606. {
  607. foreach (var s in statements)
  608. s.Resolve (ec);
  609. return true;
  610. }
  611. protected override void DoEmit (EmitContext ec)
  612. {
  613. foreach (var s in statements)
  614. s.Emit (ec);
  615. }
  616. protected override void CloneTo (CloneContext clonectx, Statement target)
  617. {
  618. StatementList t = (StatementList) target;
  619. t.statements = new List<Statement> (statements.Count);
  620. foreach (Statement s in statements)
  621. t.statements.Add (s.Clone (clonectx));
  622. }
  623. public override object Accept (StructuralVisitor visitor)
  624. {
  625. return visitor.Visit (this);
  626. }
  627. }
  628. // A 'return' or a 'yield break'
  629. public abstract class ExitStatement : Statement
  630. {
  631. protected bool unwind_protect;
  632. protected abstract bool DoResolve (BlockContext ec);
  633. public virtual void Error_FinallyClause (Report Report)
  634. {
  635. Report.Error (157, loc, "Control cannot leave the body of a finally clause");
  636. }
  637. public sealed override bool Resolve (BlockContext ec)
  638. {
  639. var res = DoResolve (ec);
  640. unwind_protect = ec.CurrentBranching.AddReturnOrigin (ec.CurrentBranching.CurrentUsageVector, this);
  641. ec.CurrentBranching.CurrentUsageVector.Goto ();
  642. return res;
  643. }
  644. }
  645. /// <summary>
  646. /// Implements the return statement
  647. /// </summary>
  648. public class Return : ExitStatement
  649. {
  650. Expression expr;
  651. public Return (Expression expr, Location l)
  652. {
  653. this.expr = expr;
  654. loc = l;
  655. }
  656. #region Properties
  657. public Expression Expr {
  658. get {
  659. return expr;
  660. }
  661. protected set {
  662. expr = value;
  663. }
  664. }
  665. #endregion
  666. protected override bool DoResolve (BlockContext ec)
  667. {
  668. if (expr == null) {
  669. if (ec.ReturnType.Kind == MemberKind.Void)
  670. return true;
  671. //
  672. // Return must not be followed by an expression when
  673. // the method return type is Task
  674. //
  675. if (ec.CurrentAnonymousMethod is AsyncInitializer) {
  676. var storey = (AsyncTaskStorey) ec.CurrentAnonymousMethod.Storey;
  677. if (storey.ReturnType == ec.Module.PredefinedTypes.Task.TypeSpec) {
  678. //
  679. // Extra trick not to emit ret/leave inside awaiter body
  680. //
  681. expr = EmptyExpression.Null;
  682. return true;
  683. }
  684. }
  685. if (ec.CurrentIterator != null) {
  686. Error_ReturnFromIterator (ec);
  687. } else if (ec.ReturnType != InternalType.ErrorType) {
  688. ec.Report.Error (126, loc,
  689. "An object of a type convertible to `{0}' is required for the return statement",
  690. ec.ReturnType.GetSignatureForError ());
  691. }
  692. return false;
  693. }
  694. expr = expr.Resolve (ec);
  695. TypeSpec block_return_type = ec.ReturnType;
  696. AnonymousExpression am = ec.CurrentAnonymousMethod;
  697. if (am == null) {
  698. if (block_return_type.Kind == MemberKind.Void) {
  699. ec.Report.Error (127, loc,
  700. "`{0}': A return keyword must not be followed by any expression when method returns void",
  701. ec.GetSignatureForError ());
  702. return false;
  703. }
  704. } else {
  705. if (am.IsIterator) {
  706. Error_ReturnFromIterator (ec);
  707. return false;
  708. }
  709. var async_block = am as AsyncInitializer;
  710. if (async_block != null) {
  711. if (expr != null) {
  712. var storey = (AsyncTaskStorey) am.Storey;
  713. var async_type = storey.ReturnType;
  714. if (async_type == null && async_block.ReturnTypeInference != null) {
  715. async_block.ReturnTypeInference.AddCommonTypeBound (expr.Type);
  716. return true;
  717. }
  718. if (async_type.Kind == MemberKind.Void) {
  719. ec.Report.Error (127, loc,
  720. "`{0}': A return keyword must not be followed by any expression when method returns void",
  721. ec.GetSignatureForError ());
  722. return false;
  723. }
  724. if (!async_type.IsGenericTask) {
  725. if (this is ContextualReturn)
  726. return true;
  727. ec.Report.Error (1997, loc,
  728. "`{0}': A return keyword must not be followed by an expression when async method returns `Task'. Consider using `Task<T>' return type",
  729. ec.GetSignatureForError ());
  730. return false;
  731. }
  732. //
  733. // The return type is actually Task<T> type argument
  734. //
  735. if (expr.Type == async_type) {
  736. ec.Report.Error (4016, loc,
  737. "`{0}': The return expression type of async method must be `{1}' rather than `Task<{1}>'",
  738. ec.GetSignatureForError (), async_type.TypeArguments[0].GetSignatureForError ());
  739. } else {
  740. block_return_type = async_type.TypeArguments[0];
  741. }
  742. }
  743. } else {
  744. // Same error code as .NET but better error message
  745. if (block_return_type.Kind == MemberKind.Void) {
  746. ec.Report.Error (127, loc,
  747. "`{0}': A return keyword must not be followed by any expression when delegate returns void",
  748. am.GetSignatureForError ());
  749. return false;
  750. }
  751. var l = am as AnonymousMethodBody;
  752. if (l != null && l.ReturnTypeInference != null && expr != null) {
  753. l.ReturnTypeInference.AddCommonTypeBound (expr.Type);
  754. return true;
  755. }
  756. }
  757. }
  758. if (expr == null)
  759. return false;
  760. if (expr.Type != block_return_type && expr.Type != InternalType.ErrorType) {
  761. expr = Convert.ImplicitConversionRequired (ec, expr, block_return_type, loc);
  762. if (expr == null) {
  763. if (am != null && block_return_type == ec.ReturnType) {
  764. ec.Report.Error (1662, loc,
  765. "Cannot convert `{0}' to delegate type `{1}' because some of the return types in the block are not implicitly convertible to the delegate return type",
  766. am.ContainerType, am.GetSignatureForError ());
  767. }
  768. return false;
  769. }
  770. }
  771. return true;
  772. }
  773. protected override void DoEmit (EmitContext ec)
  774. {
  775. if (expr != null) {
  776. expr.Emit (ec);
  777. var async_body = ec.CurrentAnonymousMethod as AsyncInitializer;
  778. if (async_body != null) {
  779. var async_return = ((AsyncTaskStorey) async_body.Storey).HoistedReturn;
  780. // It's null for await without async
  781. if (async_return != null) {
  782. async_return.EmitAssign (ec);
  783. ec.EmitEpilogue ();
  784. }
  785. ec.Emit (unwind_protect ? OpCodes.Leave : OpCodes.Br, async_body.BodyEnd);
  786. return;
  787. }
  788. ec.EmitEpilogue ();
  789. if (unwind_protect || ec.EmitAccurateDebugInfo)
  790. ec.Emit (OpCodes.Stloc, ec.TemporaryReturn ());
  791. }
  792. if (unwind_protect) {
  793. ec.Emit (OpCodes.Leave, ec.CreateReturnLabel ());
  794. } else if (ec.EmitAccurateDebugInfo) {
  795. ec.Emit (OpCodes.Br, ec.CreateReturnLabel ());
  796. } else {
  797. ec.Emit (OpCodes.Ret);
  798. }
  799. }
  800. void Error_ReturnFromIterator (ResolveContext rc)
  801. {
  802. rc.Report.Error (1622, loc,
  803. "Cannot return a value from iterators. Use the yield return statement to return a value, or yield break to end the iteration");
  804. }
  805. protected override void CloneTo (CloneContext clonectx, Statement t)
  806. {
  807. Return target = (Return) t;
  808. // It's null for simple return;
  809. if (expr != null)
  810. target.expr = expr.Clone (clonectx);
  811. }
  812. public override object Accept (StructuralVisitor visitor)
  813. {
  814. return visitor.Visit (this);
  815. }
  816. }
  817. public class Goto : Statement {
  818. string target;
  819. LabeledStatement label;
  820. bool unwind_protect;
  821. public override bool Resolve (BlockContext ec)
  822. {
  823. unwind_protect = ec.CurrentBranching.AddGotoOrigin (ec.CurrentBranching.CurrentUsageVector, this);
  824. ec.CurrentBranching.CurrentUsageVector.Goto ();
  825. return true;
  826. }
  827. public Goto (string label, Location l)
  828. {
  829. loc = l;
  830. target = label;
  831. }
  832. public string Target {
  833. get { return target; }
  834. }
  835. public void SetResolvedTarget (LabeledStatement label)
  836. {
  837. this.label = label;
  838. label.AddReference ();
  839. }
  840. protected override void CloneTo (CloneContext clonectx, Statement target)
  841. {
  842. // Nothing to clone
  843. }
  844. protected override void DoEmit (EmitContext ec)
  845. {
  846. if (label == null)
  847. throw new InternalErrorException ("goto emitted before target resolved");
  848. Label l = label.LabelTarget (ec);
  849. ec.Emit (unwind_protect ? OpCodes.Leave : OpCodes.Br, l);
  850. }
  851. public override object Accept (StructuralVisitor visitor)
  852. {
  853. return visitor.Visit (this);
  854. }
  855. }
  856. public class LabeledStatement : Statement {
  857. string name;
  858. bool defined;
  859. bool referenced;
  860. Label label;
  861. Block block;
  862. FlowBranching.UsageVector vectors;
  863. public LabeledStatement (string name, Block block, Location l)
  864. {
  865. this.name = name;
  866. this.block = block;
  867. this.loc = l;
  868. }
  869. public Label LabelTarget (EmitContext ec)
  870. {
  871. if (defined)
  872. return label;
  873. label = ec.DefineLabel ();
  874. defined = true;
  875. return label;
  876. }
  877. public Block Block {
  878. get {
  879. return block;
  880. }
  881. }
  882. public string Name {
  883. get { return name; }
  884. }
  885. public bool IsDefined {
  886. get { return defined; }
  887. }
  888. public bool HasBeenReferenced {
  889. get { return referenced; }
  890. }
  891. public FlowBranching.UsageVector JumpOrigins {
  892. get { return vectors; }
  893. }
  894. public void AddUsageVector (FlowBranching.UsageVector vector)
  895. {
  896. vector = vector.Clone ();
  897. vector.Next = vectors;
  898. vectors = vector;
  899. }
  900. protected override void CloneTo (CloneContext clonectx, Statement target)
  901. {
  902. // nothing to clone
  903. }
  904. public override bool Resolve (BlockContext ec)
  905. {
  906. // this flow-branching will be terminated when the surrounding block ends
  907. ec.StartFlowBranching (this);
  908. return true;
  909. }
  910. protected override void DoEmit (EmitContext ec)
  911. {
  912. if (!HasBeenReferenced)
  913. ec.Report.Warning (164, 2, loc, "This label has not been referenced");
  914. LabelTarget (ec);
  915. ec.MarkLabel (label);
  916. }
  917. public void AddReference ()
  918. {
  919. referenced = true;
  920. }
  921. public override object Accept (StructuralVisitor visitor)
  922. {
  923. return visitor.Visit (this);
  924. }
  925. }
  926. /// <summary>
  927. /// `goto default' statement
  928. /// </summary>
  929. public class GotoDefault : Statement {
  930. public GotoDefault (Location l)
  931. {
  932. loc = l;
  933. }
  934. protected override void CloneTo (CloneContext clonectx, Statement target)
  935. {
  936. // nothing to clone
  937. }
  938. public override bool Resolve (BlockContext ec)
  939. {
  940. ec.CurrentBranching.CurrentUsageVector.Goto ();
  941. if (ec.Switch == null) {
  942. ec.Report.Error (153, loc, "A goto case is only valid inside a switch statement");
  943. return false;
  944. }
  945. if (!ec.Switch.GotDefault) {
  946. FlowBranchingBlock.Error_UnknownLabel (loc, "default", ec.Report);
  947. return false;
  948. }
  949. return true;
  950. }
  951. protected override void DoEmit (EmitContext ec)
  952. {
  953. ec.Emit (OpCodes.Br, ec.Switch.DefaultLabel);
  954. }
  955. public override object Accept (StructuralVisitor visitor)
  956. {
  957. return visitor.Visit (this);
  958. }
  959. }
  960. /// <summary>
  961. /// `goto case' statement
  962. /// </summary>
  963. public class GotoCase : Statement {
  964. Expression expr;
  965. SwitchLabel sl;
  966. public GotoCase (Expression e, Location l)
  967. {
  968. expr = e;
  969. loc = l;
  970. }
  971. public Expression Expr {
  972. get {
  973. return this.expr;
  974. }
  975. }
  976. public override bool Resolve (BlockContext ec)
  977. {
  978. if (ec.Switch == null){
  979. ec.Report.Error (153, loc, "A goto case is only valid inside a switch statement");
  980. return false;
  981. }
  982. ec.CurrentBranching.CurrentUsageVector.Goto ();
  983. expr = expr.Resolve (ec);
  984. if (expr == null)
  985. return false;
  986. Constant c = expr as Constant;
  987. if (c == null) {
  988. ec.Report.Error (150, expr.Location, "A constant value is expected");
  989. return false;
  990. }
  991. Constant res;
  992. if (ec.Switch.IsNullable && c is NullLiteral) {
  993. res = c;
  994. } else {
  995. TypeSpec type = ec.Switch.SwitchType;
  996. res = c.Reduce (ec, type);
  997. if (res == null) {
  998. c.Error_ValueCannotBeConverted (ec, type, true);
  999. return false;
  1000. }
  1001. if (!Convert.ImplicitStandardConversionExists (c, type))
  1002. ec.Report.Warning (469, 2, loc,
  1003. "The `goto case' value is not implicitly convertible to type `{0}'",
  1004. TypeManager.CSharpName (type));
  1005. }
  1006. sl = ec.Switch.ResolveGotoCase (ec, res);
  1007. return true;
  1008. }
  1009. protected override void DoEmit (EmitContext ec)
  1010. {
  1011. ec.Emit (OpCodes.Br, sl.GetILLabel (ec));
  1012. }
  1013. protected override void CloneTo (CloneContext clonectx, Statement t)
  1014. {
  1015. GotoCase target = (GotoCase) t;
  1016. target.expr = expr.Clone (clonectx);
  1017. }
  1018. public override object Accept (StructuralVisitor visitor)
  1019. {
  1020. return visitor.Visit (this);
  1021. }
  1022. }
  1023. public class Throw : Statement {
  1024. Expression expr;
  1025. public Throw (Expression expr, Location l)
  1026. {
  1027. this.expr = expr;
  1028. loc = l;
  1029. }
  1030. public Expression Expr {
  1031. get {
  1032. return this.expr;
  1033. }
  1034. }
  1035. public override bool Resolve (BlockContext ec)
  1036. {
  1037. if (expr == null) {
  1038. ec.CurrentBranching.CurrentUsageVector.Goto ();
  1039. return ec.CurrentBranching.CheckRethrow (loc);
  1040. }
  1041. expr = expr.Resolve (ec, ResolveFlags.Type | ResolveFlags.VariableOrValue);
  1042. ec.CurrentBranching.CurrentUsageVector.Goto ();
  1043. if (expr == null)
  1044. return false;
  1045. var et = ec.BuiltinTypes.Exception;
  1046. if (Convert.ImplicitConversionExists (ec, expr, et))
  1047. expr = Convert.ImplicitConversion (ec, expr, et, loc);
  1048. else
  1049. ec.Report.Error (155, expr.Location, "The type caught or thrown must be derived from System.Exception");
  1050. return true;
  1051. }
  1052. protected override void DoEmit (EmitContext ec)
  1053. {
  1054. if (expr == null)
  1055. ec.Emit (OpCodes.Rethrow);
  1056. else {
  1057. expr.Emit (ec);
  1058. ec.Emit (OpCodes.Throw);
  1059. }
  1060. }
  1061. protected override void CloneTo (CloneContext clonectx, Statement t)
  1062. {
  1063. Throw target = (Throw) t;
  1064. if (expr != null)
  1065. target.expr = expr.Clone (clonectx);
  1066. }
  1067. public override object Accept (StructuralVisitor visitor)
  1068. {
  1069. return visitor.Visit (this);
  1070. }
  1071. }
  1072. public class Break : Statement {
  1073. public Break (Location l)
  1074. {
  1075. loc = l;
  1076. }
  1077. bool unwind_protect;
  1078. public override bool Resolve (BlockContext ec)
  1079. {
  1080. unwind_protect = ec.CurrentBranching.AddBreakOrigin (ec.CurrentBranching.CurrentUsageVector, loc);
  1081. ec.CurrentBranching.CurrentUsageVector.Goto ();
  1082. return true;
  1083. }
  1084. protected override void DoEmit (EmitContext ec)
  1085. {
  1086. ec.Emit (unwind_protect ? OpCodes.Leave : OpCodes.Br, ec.LoopEnd);
  1087. }
  1088. protected override void CloneTo (CloneContext clonectx, Statement t)
  1089. {
  1090. // nothing needed
  1091. }
  1092. public override object Accept (StructuralVisitor visitor)
  1093. {
  1094. return visitor.Visit (this);
  1095. }
  1096. }
  1097. public class Continue : Statement {
  1098. public Continue (Location l)
  1099. {
  1100. loc = l;
  1101. }
  1102. bool unwind_protect;
  1103. public override bool Resolve (BlockContext ec)
  1104. {
  1105. unwind_protect = ec.CurrentBranching.AddContinueOrigin (ec.CurrentBranching.CurrentUsageVector, loc);
  1106. ec.CurrentBranching.CurrentUsageVector.Goto ();
  1107. return true;
  1108. }
  1109. protected override void DoEmit (EmitContext ec)
  1110. {
  1111. ec.Emit (unwind_protect ? OpCodes.Leave : OpCodes.Br, ec.LoopBegin);
  1112. }
  1113. protected override void CloneTo (CloneContext clonectx, Statement t)
  1114. {
  1115. // nothing needed.
  1116. }
  1117. public override object Accept (StructuralVisitor visitor)
  1118. {
  1119. return visitor.Visit (this);
  1120. }
  1121. }
  1122. public interface ILocalVariable
  1123. {
  1124. void Emit (EmitContext ec);
  1125. void EmitAssign (EmitContext ec);
  1126. void EmitAddressOf (EmitContext ec);
  1127. }
  1128. public interface INamedBlockVariable
  1129. {
  1130. Block Block { get; }
  1131. Expression CreateReferenceExpression (ResolveContext rc, Location loc);
  1132. bool IsDeclared { get; }
  1133. bool IsParameter { get; }
  1134. Location Location { get; }
  1135. }
  1136. public class BlockVariableDeclaration : Statement
  1137. {
  1138. public class Declarator
  1139. {
  1140. LocalVariable li;
  1141. Expression initializer;
  1142. public Declarator (LocalVariable li, Expression initializer)
  1143. {
  1144. if (li.Type != null)
  1145. throw new ArgumentException ("Expected null variable type");
  1146. this.li = li;
  1147. this.initializer = initializer;
  1148. }
  1149. public Declarator (Declarator clone, Expression initializer)
  1150. {
  1151. this.li = clone.li;
  1152. this.initializer = initializer;
  1153. }
  1154. #region Properties
  1155. public LocalVariable Variable {
  1156. get {
  1157. return li;
  1158. }
  1159. }
  1160. public Expression Initializer {
  1161. get {
  1162. return initializer;
  1163. }
  1164. set {
  1165. initializer = value;
  1166. }
  1167. }
  1168. #endregion
  1169. }
  1170. Expression initializer;
  1171. protected FullNamedExpression type_expr;
  1172. protected LocalVariable li;
  1173. protected List<Declarator> declarators;
  1174. TypeSpec type;
  1175. public BlockVariableDeclaration (FullNamedExpression type, LocalVariable li)
  1176. {
  1177. this.type_expr = type;
  1178. this.li = li;
  1179. this.loc = type_expr.Location;
  1180. }
  1181. protected BlockVariableDeclaration (LocalVariable li)
  1182. {
  1183. this.li = li;
  1184. }
  1185. #region Properties
  1186. public List<Declarator> Declarators {
  1187. get {
  1188. return declarators;
  1189. }
  1190. }
  1191. public Expression Initializer {
  1192. get {
  1193. return initializer;
  1194. }
  1195. set {
  1196. initializer = value;
  1197. }
  1198. }
  1199. public FullNamedExpression TypeExpression {
  1200. get {
  1201. return type_expr;
  1202. }
  1203. }
  1204. public LocalVariable Variable {
  1205. get {
  1206. return li;
  1207. }
  1208. }
  1209. #endregion
  1210. public void AddDeclarator (Declarator decl)
  1211. {
  1212. if (declarators == null)
  1213. declarators = new List<Declarator> ();
  1214. declarators.Add (decl);
  1215. }
  1216. static void CreateEvaluatorVariable (BlockContext bc, LocalVariable li)
  1217. {
  1218. if (bc.Report.Errors != 0)
  1219. return;
  1220. var container = bc.CurrentMemberDefinition.Parent.PartialContainer;
  1221. Field f = new Field (container, new TypeExpression (li.Type, li.Location), Modifiers.PUBLIC | Modifiers.STATIC,
  1222. new MemberName (li.Name, li.Location), null);
  1223. container.AddField (f);
  1224. f.Define ();
  1225. li.HoistedVariant = new HoistedEvaluatorVariable (f);
  1226. li.SetIsUsed ();
  1227. }
  1228. public override bool Resolve (BlockContext bc)
  1229. {
  1230. return Resolve (bc, true);
  1231. }
  1232. public bool Resolve (BlockContext bc, bool resolveDeclaratorInitializers)
  1233. {
  1234. if (type == null && !li.IsCompilerGenerated) {
  1235. var vexpr = type_expr as VarExpr;
  1236. //
  1237. // C# 3.0 introduced contextual keywords (var) which behaves like a type if type with
  1238. // same name exists or as a keyword when no type was found
  1239. //
  1240. if (vexpr != null && !vexpr.IsPossibleTypeOrNamespace (bc)) {
  1241. if (bc.Module.Compiler.Settings.Version < LanguageVersion.V_3)
  1242. bc.Report.FeatureIsNotAvailable (bc.Module.Compiler, loc, "implicitly typed local variable");
  1243. if (li.IsFixed) {
  1244. bc.Report.Error (821, loc, "A fixed statement cannot use an implicitly typed local variable");
  1245. return false;
  1246. }
  1247. if (li.IsConstant) {
  1248. bc.Report.Error (822, loc, "An implicitly typed local variable cannot be a constant");
  1249. return false;
  1250. }
  1251. if (Initializer == null) {
  1252. bc.Report.Error (818, loc, "An implicitly typed local variable declarator must include an initializer");
  1253. return false;
  1254. }
  1255. if (declarators != null) {
  1256. bc.Report.Error (819, loc, "An implicitly typed local variable declaration cannot include multiple declarators");
  1257. declarators = null;
  1258. }
  1259. Initializer = Initializer.Resolve (bc);
  1260. if (Initializer != null) {
  1261. ((VarExpr) type_expr).InferType (bc, Initializer);
  1262. type = type_expr.Type;
  1263. } else {
  1264. // Set error type to indicate the var was placed correctly but could
  1265. // not be infered
  1266. //
  1267. // var a = missing ();
  1268. //
  1269. type = InternalType.ErrorType;
  1270. }
  1271. }
  1272. if (type == null) {
  1273. type = type_expr.ResolveAsType (bc);
  1274. if (type == null)
  1275. return false;
  1276. if (li.IsConstant && !type.IsConstantCompatible) {
  1277. Const.Error_InvalidConstantType (type, loc, bc.Report);
  1278. }
  1279. }
  1280. if (type.IsStatic)
  1281. FieldBase.Error_VariableOfStaticClass (loc, li.Name, type, bc.Report);
  1282. li.Type = type;
  1283. }
  1284. bool eval_global = bc.Module.Compiler.Settings.StatementMode && bc.CurrentBlock is ToplevelBlock;
  1285. if (eval_global) {
  1286. CreateEvaluatorVariable (bc, li);
  1287. } else {
  1288. li.PrepareForFlowAnalysis (bc);
  1289. }
  1290. if (initializer != null) {
  1291. initializer = ResolveInitializer (bc, li, initializer);
  1292. // li.Variable.DefinitelyAssigned
  1293. }
  1294. if (declarators != null) {
  1295. foreach (var d in declarators) {
  1296. d.Variable.Type = li.Type;
  1297. if (eval_global) {
  1298. CreateEvaluatorVariable (bc, d.Variable);
  1299. } else {
  1300. d.Variable.PrepareForFlowAnalysis (bc);
  1301. }
  1302. if (d.Initializer != null && resolveDeclaratorInitializers) {
  1303. d.Initializer = ResolveInitializer (bc, d.Variable, d.Initializer);
  1304. // d.Variable.DefinitelyAssigned
  1305. }
  1306. }
  1307. }
  1308. return true;
  1309. }
  1310. protected virtual Expression ResolveInitializer (BlockContext bc, LocalVariable li, Expression initializer)
  1311. {
  1312. var a = new SimpleAssign (li.CreateReferenceExpression (bc, li.Location), initializer, li.Location);
  1313. return a.ResolveStatement (bc);
  1314. }
  1315. protected override void DoEmit (EmitContext ec)
  1316. {
  1317. li.CreateBuilder (ec);
  1318. if (Initializer != null)
  1319. ((ExpressionStatement) Initializer).EmitStatement (ec);
  1320. if (declarators != null) {
  1321. foreach (var d in declarators) {
  1322. d.Variable.CreateBuilder (ec);
  1323. if (d.Initializer != null) {
  1324. ec.Mark (d.Variable.Location);
  1325. ((ExpressionStatement) d.Initializer).EmitStatement (ec);
  1326. }
  1327. }
  1328. }
  1329. }
  1330. protected override void CloneTo (CloneContext clonectx, Statement target)
  1331. {
  1332. BlockVariableDeclaration t = (BlockVariableDeclaration) target;
  1333. if (type_expr != null)
  1334. t.type_expr = (FullNamedExpression) type_expr.Clone (clonectx);
  1335. if (initializer != null)
  1336. t.initializer = initializer.Clone (clonectx);
  1337. if (declarators != null) {
  1338. t.declarators = null;
  1339. foreach (var d in declarators)
  1340. t.AddDeclarator (new Declarator (d, d.Initializer == null ? null : d.Initializer.Clone (clonectx)));
  1341. }
  1342. }
  1343. public override object Accept (StructuralVisitor visitor)
  1344. {
  1345. return visitor.Visit (this);
  1346. }
  1347. }
  1348. public class BlockConstantDeclaration : BlockVariableDeclaration
  1349. {
  1350. public BlockConstantDeclaration (FullNamedExpression type, LocalVariable li)
  1351. : base (type, li)
  1352. {
  1353. }
  1354. public override void Emit (EmitContext ec)
  1355. {
  1356. // Nothing to emit, not even sequence point
  1357. }
  1358. protected override Expression ResolveInitializer (BlockContext bc, LocalVariable li, Expression initializer)
  1359. {
  1360. initializer = initializer.Resolve (bc);
  1361. if (initializer == null)
  1362. return null;
  1363. var c = initializer as Constant;
  1364. if (c == null) {
  1365. initializer.Error_ExpressionMustBeConstant (bc, initializer.Location, li.Name);
  1366. return null;
  1367. }
  1368. c = c.ConvertImplicitly (li.Type);
  1369. if (c == null) {
  1370. if (TypeSpec.IsReferenceType (li.Type))
  1371. initializer.Error_ConstantCanBeInitializedWithNullOnly (bc, li.Type, initializer.Location, li.Name);
  1372. else
  1373. initializer.Error_ValueCannotBeConverted (bc, li.Type, false);
  1374. return null;
  1375. }
  1376. li.ConstantValue = c;
  1377. return initializer;
  1378. }
  1379. public override object Accept (StructuralVisitor visitor)
  1380. {
  1381. return visitor.Visit (this);
  1382. }
  1383. }
  1384. //
  1385. // The information about a user-perceived local variable
  1386. //
  1387. public class LocalVariable : INamedBlockVariable, ILocalVariable
  1388. {
  1389. [Flags]
  1390. public enum Flags
  1391. {
  1392. Used = 1,
  1393. IsThis = 1 << 1,
  1394. AddressTaken = 1 << 2,
  1395. CompilerGenerated = 1 << 3,
  1396. Constant = 1 << 4,
  1397. ForeachVariable = 1 << 5,
  1398. FixedVariable = 1 << 6,
  1399. UsingVariable = 1 << 7,
  1400. // DefinitelyAssigned = 1 << 8,
  1401. IsLocked = 1 << 9,
  1402. ReadonlyMask = ForeachVariable | FixedVariable | UsingVariable
  1403. }
  1404. TypeSpec type;
  1405. readonly string name;
  1406. readonly Location loc;
  1407. readonly Block block;
  1408. Flags flags;
  1409. Constant const_value;
  1410. public VariableInfo VariableInfo;
  1411. HoistedVariable hoisted_variant;
  1412. LocalBuilder builder;
  1413. public LocalVariable (Block block, string name, Location loc)
  1414. {
  1415. this.block = block;
  1416. this.name = name;
  1417. this.loc = loc;
  1418. }
  1419. public LocalVariable (Block block, string name, Flags flags, Location loc)
  1420. : this (block, name, loc)
  1421. {
  1422. this.flags = flags;
  1423. }
  1424. //
  1425. // Used by variable declarators
  1426. //
  1427. public LocalVariable (LocalVariable li, string name, Location loc)
  1428. : this (li.block, name, li.flags, loc)
  1429. {
  1430. }
  1431. #region Properties
  1432. public bool AddressTaken {
  1433. get {
  1434. return (flags & Flags.AddressTaken) != 0;
  1435. }
  1436. }
  1437. public Block Block {
  1438. get {
  1439. return block;
  1440. }
  1441. }
  1442. public Constant ConstantValue {
  1443. get {
  1444. return const_value;
  1445. }
  1446. set {
  1447. const_value = value;
  1448. }
  1449. }
  1450. //
  1451. // Hoisted local variable variant
  1452. //
  1453. public HoistedVariable HoistedVariant {
  1454. get {
  1455. return hoisted_variant;
  1456. }
  1457. set {
  1458. hoisted_variant = value;
  1459. }
  1460. }
  1461. public bool IsDeclared {
  1462. get {
  1463. return type != null;
  1464. }
  1465. }
  1466. public bool IsCompilerGenerated {
  1467. get {
  1468. return (flags & Flags.CompilerGenerated) != 0;
  1469. }
  1470. }
  1471. public bool IsConstant {
  1472. get {
  1473. return (flags & Flags.Constant) != 0;
  1474. }
  1475. }
  1476. public bool IsLocked {
  1477. get {
  1478. return (flags & Flags.IsLocked) != 0;
  1479. }
  1480. set {
  1481. flags = value ? flags | Flags.IsLocked : flags & ~Flags.IsLocked;
  1482. }
  1483. }
  1484. public bool IsThis {
  1485. get {
  1486. return (flags & Flags.IsThis) != 0;
  1487. }
  1488. }
  1489. public bool IsFixed {
  1490. get {
  1491. return (flags & Flags.FixedVariable) != 0;
  1492. }
  1493. }
  1494. bool INamedBlockVariable.IsParameter {
  1495. get {
  1496. return false;
  1497. }
  1498. }
  1499. public bool IsReadonly {
  1500. get {
  1501. return (flags & Flags.ReadonlyMask) != 0;
  1502. }
  1503. }
  1504. public Location Location {
  1505. get {
  1506. return loc;
  1507. }
  1508. }
  1509. public string Name {
  1510. get {
  1511. return name;
  1512. }
  1513. }
  1514. public TypeSpec Type {
  1515. get {
  1516. return type;
  1517. }
  1518. set {
  1519. type = value;
  1520. }
  1521. }
  1522. #endregion
  1523. public void CreateBuilder (EmitContext ec)
  1524. {
  1525. if ((flags & Flags.Used) == 0) {
  1526. if (VariableInfo == null) {
  1527. // Missing flow analysis or wrong variable flags
  1528. throw new InternalErrorException ("VariableInfo is null and the variable `{0}' is not used", name);
  1529. }
  1530. if (VariableInfo.IsEverAssigned)
  1531. ec.Report.Warning (219, 3, Location, "The variable `{0}' is assigned but its value is never used", Name);
  1532. else
  1533. ec.Report.Warning (168, 3, Location, "The variable `{0}' is declared but never used", Name);
  1534. }
  1535. if (HoistedVariant != null)
  1536. return;
  1537. if (builder != null) {
  1538. if ((flags & Flags.CompilerGenerated) != 0)
  1539. return;
  1540. // To avoid Used warning duplicates
  1541. throw new InternalErrorException ("Already created variable `{0}'", name);
  1542. }
  1543. //
  1544. // All fixed variabled are pinned, a slot has to be alocated
  1545. //
  1546. builder = ec.DeclareLocal (Type, IsFixed);
  1547. if (!ec.HasSet (BuilderContext.Options.OmitDebugInfo) && (flags & Flags.CompilerGenerated) == 0)
  1548. ec.DefineLocalVariable (name, builder);
  1549. }
  1550. public static LocalVariable CreateCompilerGenerated (TypeSpec type, Block block, Location loc)
  1551. {
  1552. LocalVariable li = new LocalVariable (block, GetCompilerGeneratedName (block), Flags.CompilerGenerated | Flags.Used, loc);
  1553. li.Type = type;
  1554. return li;
  1555. }
  1556. public Expression CreateReferenceExpression (ResolveContext rc, Location loc)
  1557. {
  1558. if (IsConstant && const_value != null)
  1559. return Constant.CreateConstantFromValue (Type, const_value.GetValue (), loc);
  1560. return new LocalVariableReference (this, loc);
  1561. }
  1562. public void Emit (EmitContext ec)
  1563. {
  1564. // TODO: Need something better for temporary variables
  1565. if ((flags & Flags.CompilerGenerated) != 0)
  1566. CreateBuilder (ec);
  1567. ec.Emit (OpCodes.Ldloc, builder);
  1568. }
  1569. public void EmitAssign (EmitContext ec)
  1570. {
  1571. // TODO: Need something better for temporary variables
  1572. if ((flags & Flags.CompilerGenerated) != 0)
  1573. CreateBuilder (ec);
  1574. ec.Emit (OpCodes.Stloc, builder);
  1575. }
  1576. public void EmitAddressOf (EmitContext ec)
  1577. {
  1578. ec.Emit (OpCodes.Ldloca, builder);
  1579. }
  1580. public static string GetCompilerGeneratedName (Block block)
  1581. {
  1582. // HACK: Debugger depends on the name semantics
  1583. return "$locvar" + block.ParametersBlock.TemporaryLocalsCount++.ToString ("X");
  1584. }
  1585. public string GetReadOnlyContext ()
  1586. {
  1587. switch (flags & Flags.ReadonlyMask) {
  1588. case Flags.FixedVariable:
  1589. return "fixed variable";
  1590. case Flags.ForeachVariable:
  1591. return "foreach iteration variable";
  1592. case Flags.UsingVariable:
  1593. return "using variable";
  1594. }
  1595. throw new InternalErrorException ("Variable is not readonly");
  1596. }
  1597. public bool IsThisAssigned (BlockContext ec, Block block)
  1598. {
  1599. if (VariableInfo == null)
  1600. throw new Exception ();
  1601. if (!ec.DoFlowAnalysis || ec.CurrentBranching.IsAssigned (VariableInfo))
  1602. return true;
  1603. return VariableInfo.IsFullyInitialized (ec, block.StartLocation);
  1604. }
  1605. public bool IsAssigned (BlockContext ec)
  1606. {
  1607. if (VariableInfo == null)
  1608. throw new Exception ();
  1609. return !ec.DoFlowAnalysis || ec.CurrentBranching.IsAssigned (VariableInfo);
  1610. }
  1611. public void PrepareForFlowAnalysis (BlockContext bc)
  1612. {
  1613. //
  1614. // No need for definitely assigned check for these guys
  1615. //
  1616. if ((flags & (Flags.Constant | Flags.ReadonlyMask | Flags.CompilerGenerated)) != 0)
  1617. return;
  1618. VariableInfo = new VariableInfo (this, bc.FlowOffset);
  1619. bc.FlowOffset += VariableInfo.Length;
  1620. }
  1621. //
  1622. // Mark the variables as referenced in the user code
  1623. //
  1624. public void SetIsUsed ()
  1625. {
  1626. flags |= Flags.Used;
  1627. }
  1628. public void SetHasAddressTaken ()
  1629. {
  1630. flags |= (Flags.AddressTaken | Flags.Used);
  1631. }
  1632. public override string ToString ()
  1633. {
  1634. return string.Format ("LocalInfo ({0},{1},{2},{3})", name, type, VariableInfo, Location);
  1635. }
  1636. }
  1637. /// <summary>
  1638. /// Block represents a C# block.
  1639. /// </summary>
  1640. ///
  1641. /// <remarks>
  1642. /// This class is used in a number of places: either to represent
  1643. /// explicit blocks that the programmer places or implicit blocks.
  1644. ///
  1645. /// Implicit blocks are used as labels or to introduce variable
  1646. /// declarations.
  1647. ///
  1648. /// Top-level blocks derive from Block, and they are called ToplevelBlock
  1649. /// they contain extra information that is not necessary on normal blocks.
  1650. /// </remarks>
  1651. public class Block : Statement {
  1652. [Flags]
  1653. public enum Flags
  1654. {
  1655. Unchecked = 1,
  1656. HasRet = 8,
  1657. Unsafe = 16,
  1658. HasCapturedVariable = 64,
  1659. HasCapturedThis = 1 << 7,
  1660. IsExpressionTree = 1 << 8,
  1661. CompilerGenerated = 1 << 9,
  1662. HasAsyncModifier = 1 << 10,
  1663. Resolved = 1 << 11,
  1664. YieldBlock = 1 << 12,
  1665. AwaitBlock = 1 << 13
  1666. }
  1667. public Block Parent;
  1668. public Location StartLocation;
  1669. public Location EndLocation;
  1670. public ExplicitBlock Explicit;
  1671. public ParametersBlock ParametersBlock;
  1672. protected Flags flags;
  1673. //
  1674. // The statements in this block
  1675. //
  1676. protected List<Statement> statements;
  1677. protected List<Statement> scope_initializers;
  1678. int? resolving_init_idx;
  1679. Block original;
  1680. #if DEBUG
  1681. static int id;
  1682. public int ID = id++;
  1683. static int clone_id_counter;
  1684. int clone_id;
  1685. #endif
  1686. // int assignable_slots;
  1687. public Block (Block parent, Location start, Location end)
  1688. : this (parent, 0, start, end)
  1689. {
  1690. }
  1691. public Block (Block parent, Flags flags, Location start, Location end)
  1692. {
  1693. if (parent != null) {
  1694. // the appropriate constructors will fixup these fields
  1695. ParametersBlock = parent.ParametersBlock;
  1696. Explicit = parent.Explicit;
  1697. }
  1698. this.Parent = parent;
  1699. this.flags = flags;
  1700. this.StartLocation = start;
  1701. this.EndLocation = end;
  1702. this.loc = start;
  1703. statements = new List<Statement> (4);
  1704. this.original = this;
  1705. }
  1706. #region Properties
  1707. public bool HasUnreachableClosingBrace {
  1708. get {
  1709. return (flags & Flags.HasRet) != 0;
  1710. }
  1711. set {
  1712. flags = value ? flags | Flags.HasRet : flags & ~Flags.HasRet;
  1713. }
  1714. }
  1715. public Block Original {
  1716. get {
  1717. return original;
  1718. }
  1719. protected set {
  1720. original = value;
  1721. }
  1722. }
  1723. public bool IsCompilerGenerated {
  1724. get { return (flags & Flags.CompilerGenerated) != 0; }
  1725. set { flags = value ? flags | Flags.CompilerGenerated : flags & ~Flags.CompilerGenerated; }
  1726. }
  1727. public bool Unchecked {
  1728. get { return (flags & Flags.Unchecked) != 0; }
  1729. set { flags = value ? flags | Flags.Unchecked : flags & ~Flags.Unchecked; }
  1730. }
  1731. public bool Unsafe {
  1732. get { return (flags & Flags.Unsafe) != 0; }
  1733. set { flags |= Flags.Unsafe; }
  1734. }
  1735. public List<Statement> Statements {
  1736. get { return statements; }
  1737. }
  1738. #endregion
  1739. public Block CreateSwitchBlock (Location start)
  1740. {
  1741. // FIXME: Only explicit block should be created
  1742. var new_block = new Block (this, start, start);
  1743. new_block.IsCompilerGenerated = true;
  1744. return new_block;
  1745. }
  1746. public void SetEndLocation (Location loc)
  1747. {
  1748. EndLocation = loc;
  1749. }
  1750. public void AddLabel (LabeledStatement target)
  1751. {
  1752. ParametersBlock.TopBlock.AddLabel (target.Name, target);
  1753. }
  1754. public void AddLocalName (LocalVariable li)
  1755. {
  1756. AddLocalName (li.Name, li);
  1757. }
  1758. public void AddLocalName (string name, INamedBlockVariable li)
  1759. {
  1760. ParametersBlock.TopBlock.AddLocalName (name, li, false);
  1761. }
  1762. public virtual void Error_AlreadyDeclared (string name, INamedBlockVariable variable, string reason)
  1763. {
  1764. if (reason == null) {
  1765. Error_AlreadyDeclared (name, variable);
  1766. return;
  1767. }
  1768. ParametersBlock.TopBlock.Report.Error (136, variable.Location,
  1769. "A local variable named `{0}' cannot be declared in this scope because it would give a different meaning " +
  1770. "to `{0}', which is already used in a `{1}' scope to denote something else",
  1771. name, reason);
  1772. }
  1773. public virtual void Error_AlreadyDeclared (string name, INamedBlockVariable variable)
  1774. {
  1775. var pi = variable as ParametersBlock.ParameterInfo;
  1776. if (pi != null) {
  1777. pi.Parameter.Error_DuplicateName (ParametersBlock.TopBlock.Report);
  1778. } else {
  1779. ParametersBlock.TopBlock.Report.Error (128, variable.Location,
  1780. "A local variable named `{0}' is already defined in this scope", name);
  1781. }
  1782. }
  1783. public virtual void Error_AlreadyDeclaredTypeParameter (string name, Location loc)
  1784. {
  1785. ParametersBlock.TopBlock.Repo

Large files files are truncated, but you can click here to view the full file