Repository: hylo-lang/hylo (swift)

Issue:
Fatal error while using projection
For the following code:
```swift
fun pointer_to_function(_ f: sink ()->Int) -> CVoidPointer {
  return c_void_pointer[to: f]
}
```
we get the following error:
```
Sources/IR/Emitter.swift:1338: Fatal error: unexpected SubscriptCallExpr at location: Examples/test_bug.hylo:2:10
```

This is coming from `Emitter.emitStore<T: ExprID>(value e: T, to storage: Operand)`

The `c_void_pointer` is defined (in standard library) as:
```
public subscript c_void_pointer<T>(to x: T): CVoidPointer {
  let { yield CVoidPointer(base: Builtin.address(of: x)) }
}
```

Pull request:
Fixes #1245.

Patch:
diff --git a/Sources/Core/AST/AST.swift b/Sources/Core/AST/AST.swift
index 266bf36a1..e037f8ce0 100644
--- a/Sources/Core/AST/AST.swift
+++ b/Sources/Core/AST/AST.swift
@@ -436,6 +436,11 @@ public struct AST {
     }
   }
 
+  /// Retutns the declaration of the implementation of `d` with effect `a`, if any.
+  public func implementation(_ a: AccessEffect, of d: SubscriptDecl.ID) -> SubscriptImpl.ID? {
+    self[d].impls.first(where: { (i) in self[i].introducer.value == a })
+  }
+
   /// Returns `true` iff `s` is a consuming for-loop.
   public func isConsuming(_ s: ForStmt.ID) -> Bool {
     self[self[self[s].binding].pattern].introducer.value.isConsuming
diff --git a/Sources/IR/Emitter.swift b/Sources/IR/Emitter.swift
index 5baa90443..5c11ba8fa 100644
--- a/Sources/IR/Emitter.swift
+++ b/Sources/IR/Emitter.swift
@@ -1328,6 +1328,8 @@ struct Emitter {
       emitStore(RemoteExpr.ID(e)!, to: storage)
     case SequenceExpr.self:
       emitStore(SequenceExpr.ID(e)!, to: storage)
+    case SubscriptCallExpr.self:
+      emitStore(SubscriptCallExpr.ID(e)!, to: storage)
     case StringLiteralExpr.self:
       emitStore(StringLiteralExpr.ID(e)!, to: storage)
     case TupleExpr.self:
@@ -1599,6 +1601,19 @@ struct Emitter {
     }
   }
 
+  /// Inserts the IR for storing the value of `e` to `storage`.
+  private mutating func emitStore(_ e: SubscriptCallExpr.ID, to storage: Operand) {
+    let (callee, arguments) = emitOperands(e)
+    guard ast.implementation(.sink, of: callee.bundle) != nil else {
+      let n = ast.name(of: callee.bundle)
+      report(.error(n, hasNoSinkImplementationAt: program[e].callee.site))
+      return
+    }
+
+    _ = arguments
+    UNIMPLEMENTED("sink subscript")
+  }
+
   /// Inserts the IR for storing the value of `e` to `storage`.
   private mutating func emitStore(_ e: StringLiteralExpr.ID, to storage: Operand) {
     emitStore(string: ast[e].value, to: storage, at: ast[e].site)
@@ -1882,6 +1897,21 @@ struct Emitter {
     return result
   }
 
+  /// Inserts the IR generating the operands of the subscript call `e`.
+  private mutating func emitOperands(
+    _ e: SubscriptCallExpr.ID
+  ) -> (callee: BundleReference<SubscriptDecl>, arguments: [Operand]) {
+    // Explicit arguments are evaluated first, from left to right.
+    let explicitArguments = emitArguments(
+      to: ast[e].callee, in: CallID(e),
+      usingExplicit: ast[e].arguments, synthesizingDefaultAt: .empty(atEndOf: ast[e].site))
+
+    // Callee and captures are evaluated next.
+    let (callee, captures) = emit(subscriptCallee: ast[e].callee)
+
+    return (callee, captures + explicitArguments)
+  }
+
   /// Inserts the IR for the argument `e` passed to a parameter of type `parameter`.
   ///
   /// - Parameters:
@@ -2469,15 +2499,7 @@ struct Emitter {
 
   /// Inserts the IR for lvalue `e`.
   private mutating func emitLValue(_ e: SubscriptCallExpr.ID) -> Operand {
-    // Explicit arguments are evaluated first, from left to right.
-    let explicitArguments = emitArguments(
-      to: ast[e].callee, in: CallID(e),
-      usingExplicit: ast[e].arguments, synthesizingDefaultAt: .empty(atEndOf: ast[e].site))
-
-    // Callee and captures are evaluated next.
-    let (callee, captures) = emit(subscriptCallee: ast[e].callee)
-    let arguments = captures + explicitArguments
-
+    let (callee, arguments) = emitOperands(e)
     let s = module.makeProjectBundle(
       applying: .init(callee, in: insertionScope!), to: arguments, at: ast[e].site)
     return insert(s)!
@@ -3080,6 +3102,12 @@ extension Diagnostic {
     .error("return statement in subscript", at: ast[s].introducerSite)
   }
 
+  fileprivate static func error(
+    _ n: Name, hasNoSinkImplementationAt site: SourceRange
+  ) -> Diagnostic {
+    .error("cannot use '\(n)' to form a rvalue: subscript has no 'sink' implementation", at: site)
+  }
+
   fileprivate static func warning(unreachableStatement s: AnyStmtID, in ast: AST) -> Diagnostic {
     .error("statement will never be executed", at: .empty(at: ast[s].site.first()))
   }


Test patch:
diff --git a/Tests/HyloTests/TestCases/Lowering/InvalidRvalue.hylo b/Tests/HyloTests/TestCases/Lowering/InvalidRvalue.hylo
new file mode 100644
index 000000000..ed834d690
--- /dev/null
+++ b/Tests/HyloTests/TestCases/Lowering/InvalidRvalue.hylo
@@ -0,0 +1,12 @@
+//- lowerToFinishedIR expecting: failure
+
+subscript s(_ x: Int): Int {
+  let { yield x }
+}
+
+public fun main() {
+  let x = 42
+
+  //! @+1 diagnostic cannot use 's(_:)' to form a rvalue: subscript has no 'sink' implementation
+  var y = s[x]
+}