1. 19 2月, 2018 3 次提交
  2. 17 2月, 2018 1 次提交
    • J
      Rename to CompileStandardAndVerify · 75463028
      Jared Parsons 提交于
      This unifies our API naming convention. When standard is in the name
      then we are using the netstandard2.0 API set and when it is not then it
      is the simple desktop mscorlib46.
      
      Both variants are necessary for CompileAndVerify style functions because
      many of our tests that use it can only run on desktop or simply need to
      have some of the netstandard2.0 API set missing.
      75463028
  3. 09 2月, 2018 1 次提交
  4. 05 1月, 2018 1 次提交
  5. 24 10月, 2017 1 次提交
  6. 13 10月, 2017 1 次提交
  7. 05 10月, 2017 1 次提交
  8. 16 9月, 2017 1 次提交
  9. 02 9月, 2017 1 次提交
  10. 25 8月, 2017 1 次提交
    • A
      Add fields as members of synthesized structs (#21649) · 8dd264ba
      Andy Gocke 提交于
      In order for EnC and other mechanisms to work we have to add synthesized
      members to a list in the CommonPEModuleBuilder for a compilation (these
      synthesized members are then queried as part of compilation stages).
      If those members are struct fields, we don't add them to the struct
      definition, only to the list of synthesized members. This works for
      emit, since we explicitly emit everything in the synthesized list, but
      it doesn't work for any compiler pass that examines the members of the
      struct for semantically meaningful reasons.
      
      This is the case for the CaptureWalker for async and iterator
      expressions. The walker checks the members of structs when a field of a
      struct is assigned to see if the struct has been assigned piecewise
      (each of its members has been assigned individually). If so, it will
      mark the entire struct as assigned. By not including synthesized fields
      as proper members of the struct type, the assignment pass believes that
      many fields have been assigned that have not, and thus marks the full
      struct as assigned, leading to losing track of variables captured across
      await/yield statements.
      
      This PR fixes the problem by adding the fields to the
      SynthesizedContainer, but exlcuding them from emit, since we should
      continue to use the emit mechanism used for CommonPEModuleBuilder.
      
      Fixes #21409
      8dd264ba
  11. 19 8月, 2017 1 次提交
  12. 17 8月, 2017 1 次提交
    • A
      Remove LocalFunctionRewriting pass (#21408) · e887a8ab
      Andy Gocke 提交于
      
      Perform synthesis of closure methods in an early pass before visitation,
      meaning we no longer need to do a second visitation of the tree to lower
      local functions.
      
      The baselines have been changed because we now do closure id and
      synthessis in order of closure visitation, rather than bound node
      visitation. Closure visitation visits all the closures in a given scope,
      then recurs into nested scopes, while BoundNode visitation treats
      closures as scopes themselves, so nested closures are visited before
      closures declared in the same scope.
      
      Fixes https://github.com/dotnet/roslyn/projects/26#card-3753331
      e887a8ab
  13. 16 8月, 2017 1 次提交
    • A
      Fix bug in 'this' optimization for classes (#21510) · 5d6f76f2
      Andy Gocke 提交于
      In the introduction of the new 'this' optimization routine,
      one of the things which was changed was to treat 'this' more
      like a formal parameter of the method, as opposed to a variable
      living in an implicit, higher scope. This has some advantages
      in simplicity for analysis, but created a problem when it came
      to proxies. The current analysis builds the proxy list by walking
      the tree and finding all captured variables and adding them
      to the proxy dictionary keyed by the original variable symbol.
      For instance, if a local variable is captured to a field, during
      rewriting it will be added to the proxy list as (original symbol,
      hoisted field). Since most symbols are only ever captured to a
      single replacement field, this usually works fine -- all proxies
      can exist side-by-side in the proxy list since there is no intersection.
      
      However, this is not true for captured environment pointers. When
      a new environment is introduced, a local will be created to point
      to that environment. That local may itself be captured by nested
      variables, creating a linked list from nested scopes to parent scope.
      Most notably, *multiple* nested environments may capture the *same*
      environment pointer in *different* hoisted fields. This means that
      the proxies dictionary cannot hold all mappings at once, since the
      mapping for a given captured environment pointer will depend on the
      current scope.
      
      The current code actually accounts for this already by adding a
      captured environment pointer to the proxy list on a nested scope's
      introduction, and removing it upon leaving that scope.
      
      By changing 'this' to be treated like a formal parameter, I
      circumvented this logic, introducing a bug. When two scopes tried
      to capture the 'this' pointer, the compiler crashed due to trying
      to add two mappings to the same key.
      
      This change fixes this problem by treating the 'this' parameter
      like an environment pointer for the purposes of capturing and
      hoisting. It's possible that we want to treat it like a formal
      parameter, but if so it's probably better to treat all captured
      environment pointers the same way and introduce a scope-aware
      notion of proxies, rather than having a global dictionary.
      
      Fixes #21506
      5d6f76f2
  14. 14 8月, 2017 1 次提交
  15. 12 8月, 2017 2 次提交
  16. 11 8月, 2017 1 次提交
    • A
      Remove RemoveUnneededReferences from LamdaRewriter (#21367) · caa78300
      Andy Gocke 提交于
      Currently, the lambda rewriter has an early optimization pass in
      analysis that tries to find all local functions that only capture 'this'
      and remove references to local functions that do the same. There are two
      problems with this approach:
      
          1) Generally, removing information from the tree is a bad idea
          because it hurts further analysis passes that may have needed that
          information.
      
          2) The optimization strategy itself is very tricky and has a number
          of complex corner cases. This has lead to bugs, for example #19033.
      
      This PR deletes the current method and adds a new optimization routine
      at the end of the analysis, operating on assigned scopes and
      environments rather than removing captured variable analysis. The new
      optimization is as follows: if we end up with an environment containing
      only 'this', the environment can be removed, all containing methods can
      be moved to the top-level type, and all environments which capture the
      'this' environment can instead directly capture the 'this' parameter.
      This produces almost the same results as the previous optimization, but
      is easier to validate as an algebraic equivalence.
      
      The baseline changes come from the new optimization being less aggressive 
      about moving functions which only capture 'this' to the top level. This
      appears to be a wash -- some codegen gets slightly better, some gets
      slightly worse.
      
      Fixes #19033
      Fixes #20577
      caa78300
  17. 08 8月, 2017 1 次提交
    • A
      Re-baseline some emit tests · 343ada1b
      Andy Gocke 提交于
      The frame creation pass now considers scope of captured variable
      introduction instead of closure creation, so the ordering can change if
      two or more nested functions access variables 'outside-in', e.g.
      
      ```csharp
      {
          int x = 0;
          {
              int y = 0;
              int L1() => y;
      
              {
                   int z = 0;
                   int L2() => x;
              }
          }
      }
      ```
      
      If we visit closures in-order in the previous example, we create frames
      for L1, then L2. If we visit captured variables scopes, however, we
      visit `x` (captured by L2), then `y` (captued by L1).
      343ada1b
  18. 02 8月, 2017 1 次提交
  19. 18 7月, 2017 1 次提交
    • A
      Remove CapturedVariablesByLambda (#20878) · e240a70b
      Andy Gocke 提交于
      Swaps out all uses of CapturedVariablesByLambda for functions on the
      Scope tree.
      
      The reason the baseline changed is that the order of enumerating closures changed. I briefly looked into matching the behavior, but the problem is that the closure order in the old visitors is determined by the visitation of captured variables, not visitation of the closures themselves. More specifically, an item is only added to the CapturedVariablesByLambda dictionary when ReferenceVariable encounters a captured variable.
      
      In contrast, the visitation of the Scope tree looks at closures in an in-order traversal of the tree, stopping at the first introduced closure, not necessarily the closure which first captured a variable.
      
      One obvious consequence of this changing is that the old ordering for a series of nested lambdas was effectively post-order -- the interior closures would be added to the visitation first, since they would be added from the perspective of the captured variable looking up, instead of the visitor looking down. This particular case is responsible for all the baseline changes that I have seen.
      
      When I looked into replicating this traversal order I found it complicated and pretty counter-intuitive. Since the baseline change was so low in emitted IL, I thought it better to keep a very natural in-order tree traversal and just rebaseline a few tests.
      
      Fixes https://github.com/dotnet/roslyn/projects/26#card-3753318
      e240a70b
  20. 30 6月, 2017 1 次提交
    • A
      Fix bug in closure rewriting (#20198) · f0aec404
      Andy Gocke 提交于
      When lowering local functions that capture struct frames, the frames are
      added as ref parameters to the lowered method. Normally, when the local
      function captures variables from multiple levels up the intermediate
      closures are also rewritten to take the ref parameters. However, if one
      of the intermediate closures captures no variables, the closure
      conversion code can skip adding ref environments to that closure. This
      can cause the inner-most closure to no longer have access to all of the
      ref structs it expects, which crashes the compiler.
      
      Fixes #18814, #18918
      f0aec404
  21. 20 6月, 2017 1 次提交
  22. 17 5月, 2017 1 次提交
  23. 16 5月, 2017 1 次提交
  24. 29 4月, 2017 2 次提交
  25. 08 4月, 2017 1 次提交
  26. 20 3月, 2017 1 次提交
    • A
      Allow closures to take both struct- and class-based capture environments (#16908) · d6e70325
      Andy Gocke 提交于
      Lambda rewriting currently allows frames to be structs in the instance
      where
      
      The variables in the frame are not captured by any closures
      converted to delegates.
      
      A closure nested inside the struct closure captures a separate
      variable that does require a class frame.
      
      This poses a problem when the "outer" closure is in the same frame as
      the variable that requires a class closure. The problem is that we treat
      scopes and frames as essentially the same thing -- if any scope is
      perceived to require a particular environment type, all captured
      variables in that scope will be captured on that frame and all closures
      will be lowered onto that frame.
      
      This creates a conflict between class-based environment capturing, where
      we want to capture the frame pointer as a field, and struct-based frame
      capturing, where we want to add arguments as ref parameters. Doing both
      results in breaking the delegate contract (no signature rewriting) or
      losing required struct arguments to intermediate closures.
      
      To elaborate on the problem here, let's consider the example:
      
      ```csharp
      using System;
      class C
      {
          public void M()
          {
              int x = 0;
              {
                  int y= 0;
                  void Local()
                  {
                      if (x == 0)
                      {
                          Action a = () => y++;
                          a();
                      }
                  }
                  Local();
              }
          }
      }
      ```
      
      The current problem in the compiler is in the code now in GetStructClosures. The previous implementation only built struct closure if the closure was being lowered onto a struct frame.
      
      However, in the example, y is being captured by a lambda, meaning that y must be in a class frame. Since Local lives in the same scope it also lives in the same frame and contains the lambda capturing y, meaning that it must live in a class frame as well. Of course, it is not converted to a delegate, nor does it capture any variables that are captured by closures converted to delegates, so its signature is free to be rewritten to take variables which are not captured by closures converted to delegates as struct environment parameters.
      
      Here is the expected lowering for the previous example:
      
      ```csharp
      void M()
      {
          var env1 = new Env1();
          env1.x = 0;
          var env2 = new Env2();
          env2.y = 0;
          env2.<>_L(ref env1);
      }
      
      struct Env1
      {
          public int x;
      }
      
      class Env2
      {
          public int y;
          public void <>_L(ref Env1 env1)
          {
              if (env1.x == 0)
              {
                  var env3 = new Env3();
                  env3.env2 = this;
                  Action a = env3.<>_anon;
                  a();
              }
          }
      }
      
      class Env3
      {
           Env2 env2;
           public void <>_anon() => this.env2.y++;
      }
      ```
      
      The problem comes when calculating the struct frames needed to be passed to Local. In the current implementation, unless the "container" is a struct, no struct frames are added. If we fix that to check for struct frames that are required as parent frames, regardless of the type of container we run into another problem.
      
      In this case, the lambda also includes struct frames in its parent "context", but adding any struct frames to a closure that is converted to a delegate is incorrect.
      
      The previous problem can be solved by a check to see if the closure can take new ref parameters. This is true for all closures except for ones marked async or iterators or ones converted to delegates. This works because of something we already know from the analysis: if we assume that struct environments are only created when the their capturing closure can take ref parameters, we can assume that any struct environments in scope are "safe" to use, even if those frames are in the "parent context" of the closure.
      
      Fixes #16895
      d6e70325
  27. 07 3月, 2017 1 次提交
    • A
      Make local function default parameter value binding lazy (#17014) · 2b6d6f29
      Andy Gocke 提交于
      Make local function default parameter value binding lazy
      
      Current strict binding can cause circularity problems when local
      functions are referenced. This change causes local functions to use lazy
      default parameter binding, similar to methods, and then forces their
      construction when diagnostics are requested for the local function.
      
      This also requires a mechanism for recording declaration diagnostics
      outside of adding to the compilation's DeclarationDiagnostics. A new
      type, DeclarationDiagnosticStore is introduced as an abstraction to
      store declaration diagnostics on either the compilation or in a local
      DiagnosticBag, depending on the needs of the symbol storing diagnostics.
      
      Fixes #16451, #17293
      2b6d6f29
  28. 28 1月, 2017 1 次提交
  29. 25 1月, 2017 1 次提交
    • A
      Disallow attributes in local function definitions (#16498) · 81a092b6
      Andy Gocke 提交于
      Attributes will not be permitted on type parameters or parameters of
      local functions. This matches the existing behavior for the return type
      and symbol itself, neither of which allow attributes to be applied to
      them.
      
      Fixes #1640
      81a092b6
  30. 14 1月, 2017 1 次提交
  31. 06 1月, 2017 1 次提交
  32. 21 12月, 2016 1 次提交
  33. 20 12月, 2016 1 次提交
    • A
      Fix calling generic local functions recursively (#15968) · d09d3100
      Andy Gocke 提交于
      There were two root causes here:
      
          1) The rewriter was treating the difference between the symbol and
             `symbol.ConstructedFrom` as whether or not there were any type
             parameters remaining that may need substitution. This is invalid
             for recursive local functions.
      
          2) The local function reference rewriter was including type
             parameters from the containing type in the list of parameters to
             substitute. This should happen iff the containing type is a
             lambda frame used to capture variables, which is not always the
             case for local functions (although it is always the case for
             lambdas).
      
      Fixes #15751
      d09d3100
  34. 18 12月, 2016 1 次提交
    • A
      Fix local function capturing by another local function (#15773) · a7d43ec6
      Andy Gocke 提交于
      Local functions have already implemented their own frame management,
      including frame pointer "capturing" (which is implemented by passing a
      list of frames to the local function by-ref, rather than traditional
      lambda capturing which is implemented by keeping a linked list of frame
      pointers to parent frames).
      
      PR #14736 wired up local function lowering to the lambda frame pointer
      machinery, which is necessary for when a local function is captured by a
      lambda or converted to a delegate, but in the process it diverted
      control flow for pure local function capturing to the frame pointer
      machinery, which can't handle the structure of local function struct
      frame pointers.
      
      This PR resolves the issue by restoring the control flow for local
      functions capturing other local functions with by-ref struct frames.
      
      Fixes #15599
      a7d43ec6
  35. 14 12月, 2016 1 次提交
    • A
      Inherit unsafe regions in local functions (#15596) · c51325b0
      Andy Gocke 提交于
      When local functions are declared in unsafe regions (unsafe statement,
      unsafe member, unsafe type), their bodies should be considered unsafe
      regions, even if unsafe is not a declaration modifier on the local
      function.
      
      Fixes #13172
      c51325b0
  36. 01 12月, 2016 1 次提交
    • A
      Ignore use-before-declaration in local functions (#15339) (#15584) · d11bcc84
      Andy Gocke 提交于
      Prior to C# 7 we tried to avoid giving duplicate errors
      when the user used a variable before it was declared (which
      is both a use-before-declared and a use-before-assigned error),
      but the line here is blurred with local functions, which can
      use variables before they are declared in subtle ways that can't
      be detected based on declaration order in syntax.
      
      It may be possible to provide the earlier behavior, but the
      current optimization is definitely insufficient and hides
      legitimate errors in user programs.
      
      Fixes #15298
      Fixes #15322
      
      (cherry picked from commit 1c8372ce)
      d11bcc84