# RUN: python -m toy %s --emit=ast | filecheck %s --strict-whitespace --match-full-lines

# User defined generic function that operates on unknown shaped arguments.
def multiply_transpose(a, b) {
  return transpose(a) * transpose(b);
}

def main() {
  # Define a variable `a` with shape <2, 3>, initialized with the literal value.
  # The shape is inferred from the supplied literal.
  var a = [[1, 2, 3], [4, 5, 6]];
  # b is identical to a, the literal array is implicitly reshaped: defining new
  # variables is the way to reshape arrays (element count in literal must match
  # the size of specified shape).
  var b<2, 3> = [1, 2, 3, 4, 5, 6];

  # This call will specialize `multiply_transpose` with <2, 3> for both
  # arguments and deduce a return type of <2, 2> in initialization of `c`.
  var c = multiply_transpose(a, b);
  # A second call to `multiply_transpose` with <2, 3> for both arguments will
  # reuse the previously specialized and inferred version and return `<2, 2>`
  var d = multiply_transpose(b, a);
  # A new call with `<2, 2>` for both dimension will trigger another
  # specialization of `multiply_transpose`.
  var e = multiply_transpose(b, c);
  # Finally, calling into `multiply_transpose` with incompatible shape will
  # trigger a shape inference error.
  var f = multiply_transpose(transpose(a), c);
}


#      CHECK: Module:
# CHECK-NEXT:   Function
# CHECK-NEXT:     Proto 'multiply_transpose' @{{.*}}ast.toy:4:1
# CHECK-NEXT:     Params: [a, b]
# CHECK-NEXT:     Block {
# CHECK-NEXT:       Return
# CHECK-NEXT:         BinOp: * @{{.*}}ast.toy:5:25
# CHECK-NEXT:           Call 'transpose' [ @{{.*}}ast.toy:5:10
# CHECK-NEXT:             var: a @{{.*}}ast.toy:5:20
# CHECK-NEXT:           ]
# CHECK-NEXT:           Call 'transpose' [ @{{.*}}ast.toy:5:25
# CHECK-NEXT:             var: b @{{.*}}ast.toy:5:35
# CHECK-NEXT:           ]
# CHECK-NEXT:     } // Block
# CHECK-NEXT:   Function
# CHECK-NEXT:     Proto 'main' @{{.*}}ast.toy:8:1
# CHECK-NEXT:     Params: []
# CHECK-NEXT:     Block {
# CHECK-NEXT:       VarDecl a<> @{{.*}}ast.toy:11:3
# CHECK-NEXT:         Literal: <2, 3>[ <3>[ 1.000000e+00, 2.000000e+00, 3.000000e+00], <3>[ 4.000000e+00, 5.000000e+00, 6.000000e+00]] @{{.*}}ast.toy:11:11
# CHECK-NEXT:       VarDecl b<2, 3> @{{.*}}ast.toy:15:3
# CHECK-NEXT:         Literal: <6>[ 1.000000e+00, 2.000000e+00, 3.000000e+00, 4.000000e+00, 5.000000e+00, 6.000000e+00] @{{.*}}ast.toy:15:17
# CHECK-NEXT:       VarDecl c<> @{{.*}}ast.toy:19:3
# CHECK-NEXT:         Call 'multiply_transpose' [ @{{.*}}ast.toy:19:11
# CHECK-NEXT:           var: a @{{.*}}ast.toy:19:30
# CHECK-NEXT:           var: b @{{.*}}ast.toy:19:33
# CHECK-NEXT:         ]
# CHECK-NEXT:       VarDecl d<> @{{.*}}ast.toy:22:3
# CHECK-NEXT:         Call 'multiply_transpose' [ @{{.*}}ast.toy:22:11
# CHECK-NEXT:           var: b @{{.*}}ast.toy:22:30
# CHECK-NEXT:           var: a @{{.*}}ast.toy:22:33
# CHECK-NEXT:         ]
# CHECK-NEXT:       VarDecl e<> @{{.*}}ast.toy:25:3
# CHECK-NEXT:         Call 'multiply_transpose' [ @{{.*}}ast.toy:25:11
# CHECK-NEXT:           var: b @{{.*}}ast.toy:25:30
# CHECK-NEXT:           var: c @{{.*}}ast.toy:25:33
# CHECK-NEXT:         ]
# CHECK-NEXT:       VarDecl f<> @{{.*}}ast.toy:28:3
# CHECK-NEXT:         Call 'multiply_transpose' [ @{{.*}}ast.toy:28:11
# CHECK-NEXT:           Call 'transpose' [ @{{.*}}ast.toy:28:30
# CHECK-NEXT:             var: a @{{.*}}ast.toy:28:40
# CHECK-NEXT:           ]
# CHECK-NEXT:           var: c @{{.*}}ast.toy:28:44
# CHECK-NEXT:         ]
