[Chapel Merge] dyno: resolve nested init calls

Branch: refs/heads/main
Revision: 5822073813d9a6230a68e07fd5d782c0cab117f3
Author: DanilaFe
Link: dyno: resolve nested init calls by DanilaFe · Pull Request #24906 · chapel-lang/chapel · GitHub
Log Message:
dyno: resolve nested init calls (#24906)

Closes dyno: calls to initializers from other initializers aren't reflected. · Issue #24854 · chapel-lang/chapel · GitHub. Closes
https://github.com/Cray/chapel-private/issues/6182 (sprint task).

This PR adjusts the InitResolver to support calls like this.init
inside other init procedures.

To make this work, the PR does the following things:

  1. It disallows calls to 'init' on anything other than 'super' and
    'this'. As far as I know, this is already effectively the standard for
    Chapel; however, it was not enforced. As a result, the following program
    -- which is legal on main -- is now illegal.
    record myRec {
        var x: int;
    
        proc init(x: int, y: int) {
            this.x = x + y;
        }
    
        proc init(x: int) {
            init(x, 0);
        }
    
        proc init() {}
    }
    
    record container {
      var r: myRec;
    
      proc init() {
        init this;
        r.init(10); // bad bad bad
      }
    }
    
    var c: container;
    

By doing so, the PR makes it possible for the InitResolver to
syntactically detect calls such as this.init(). By doing this, in
turn, we can start representing their effects on the resolution state.
2. Adding new handling methods to InitResolver that operate on
CallResolutionResults in addition to AST nodes. This is required
because the effects of calling this.init depend on which overload of
init is called; as such, we want to go through the usual mechanism for
resolving the initializer. Doing so using CallResolutionResults makes
the most sense. As a result of this PR, the handleCallExpr follows up
resolution with handleResoledCall, which descends into the
InitResolver.

  • When handling init, the InitResolver populates the individual
    field states as if they were assigned to. This is useful because the
    calls to 'this.init' need to fit into the existing framework of
    initialization: handling branches, merging intermediate results, etc.
  • This also requires a slight adjustment to the handleCallExpr to stop
    skipping call resolution when the receiver formal is generic. The this
    in this.init for a generic method is going to be generic, but that
    should not stop us from performing resolution.

As a result, dyno: calls to initializers from other initializers aren't reflected. · Issue #24854 · chapel-lang/chapel · GitHub is
resolved; a major consequence of that is that ranges with the by
operator (mentioned in dyno: (almost) resolve nontrivial ranges by DanilaFe · Pull Request #24853 · chapel-lang/chapel · GitHub)
now resolve correctly: the constructor that previously threw away the
stride now properly takes it into account. I was able to validate that
the implementation of ranges in Dyno works with strides as one would
expect.

Reviewed by @benharsh -- thanks!

Testing

  • paratest
  • dyno tests

Compare: Comparing b35a6b00fc1fbfc090376fbfc26160348b00673b...f4cd1c3e87fd55b427ab55b325c2bb24b5862cc8 · chapel-lang/chapel · GitHub

Diff:
M frontend/include/chpl/resolution/resolution-error-classes-list.h
M frontend/lib/resolution/InitResolver.cpp
M frontend/lib/resolution/InitResolver.h
M frontend/lib/resolution/Resolver.cpp
M frontend/lib/resolution/resolution-error-classes-list.cpp
M frontend/lib/uast/post-parse-checks.cpp
M frontend/test/resolution/testInitSemantics.cpp
M frontend/test/resolution/testRanges.cpp
A test/errors/parsing/initnotthis.1.good
A test/errors/parsing/initnotthis.2.good
A test/errors/parsing/initnotthis.chpl
https://github.com/chapel-lang/chapel/pull/24906.diff