Repository: hylo-lang/hylo (swift)

Issue:
Various failed attempts to form pointer to uninitialized variable
/cc @lucteo 

Examples are shown below with the various failures.  Surely one of these should work?

I test with `swift run hc --import-builtin x.hylo -o /tmp/x && /tmp/x`

I have 8bc61e0bc checked out.

```
/*
public subscript mutable_pointer_for_initialization<T>(to
  x: // x.hylo:8.59-60: error: missing return in function expected to return 'PointerToMutable<T>'
  set T
): PointerToMutable<T> {
  set { yield PointerToMutable(base: Builtin.address(of: x)) }
}
 */

/*
public fun initialize<T, E, R>(_
  x: // x.hylo:8.59-60: error: missing return in function expected to return 'PointerToMutable<T>'
  set T, _ initializer: [E](PointerToMutable<T>)->R
) -> R {
  return initializer(PointerToMutable(base: Builtin.address(of: x)))
}
*/

/*
 // IR/Emitter.swift:1233: Fatal error: Unexpectedly found nil while unwrapping an Optional value
public subscript mutable_pointer_for_initialization<T>(to x: set T): PointerToMutable<T> {
  return PointerToMutable(base: Builtin.address(of: x))
}
 */

/*
public typealias Initializer<T, E, R> = [E](PointerToMutable<T>)->R

public fun initialize<T, E, R>(_ x: set T, _ initializer: Initializer<T,E,R>) -> R {
  // x.hylo:19.10-21: error: cannot call value of type 'Initializer<T, E, R>' as a function
  return initializer(PointerToMutable(base: Builtin.address(of: x)))
}
 */

/*
public typealias Initializer<T, E, R> = [E](PointerToMutable<T>) inout->R

public fun initialize<T, E, R>(_ x: set T, _ initializer: inout Initializer<T,E,R>) -> R {
  // x.hylo:23.10-22: error: cannot call value of type 'Initializer<T, E, R>' as a function
  return &initializer(PointerToMutable(base: Builtin.address(of: x)))
}
*/
```

Pull request:
Fixes the compiler trap observed in #1239

Patch:
diff --git a/Sources/IR/Emitter.swift b/Sources/IR/Emitter.swift
index 01e50b054..c2b1ef77c 100644
--- a/Sources/IR/Emitter.swift
+++ b/Sources/IR/Emitter.swift
@@ -67,12 +67,11 @@ struct Emitter {
 
   /// The address of the return value in the current function, if any.
   private var returnValue: Operand? {
-    guard
-      let f = insertionFunction,
-      let b = module.entry(of: f),
-      !module[f].isSubscript
-    else { return nil }
-    return .parameter(b, module[f].inputs.count)
+    if let f = insertionFunction, let b = module.entry(of: f), !module[f].isSubscript {
+      return .parameter(b, module[f].inputs.count)
+    } else {
+      return nil
+    }
   }
 
   /// Reports the given diagnostic.
@@ -1228,7 +1227,13 @@ struct Emitter {
     return (startIndex: start, endIndex: end)
   }
 
+  /// Inserts the IR for `s`, returning its effect on control flow.
   private mutating func emit(returnStmt s: ReturnStmt.ID) -> ControlFlow {
+    if module[insertionFunction!].isSubscript {
+      report(.error(returnInSubscript: s, in: ast))
+      return .next
+    }
+
     if let e = ast[s].value {
       emitStore(value: e, to: returnValue!)
     } else {
@@ -3071,6 +3076,10 @@ extension Diagnostic {
     .error("integer literal '\(s)' overflows when stored into '\(t)'", at: site)
   }
 
+  fileprivate static func error(returnInSubscript s: ReturnStmt.ID, in ast: AST) -> Diagnostic {
+    .error("return statement in subscript", at: ast[s].introducerSite)
+  }
+
   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/ReturnInSubscript.hylo b/Tests/HyloTests/TestCases/Lowering/ReturnInSubscript.hylo
new file mode 100644
index 000000000..4b21ed55f
--- /dev/null
+++ b/Tests/HyloTests/TestCases/Lowering/ReturnInSubscript.hylo
@@ -0,0 +1,6 @@
+//- lowerToFinishedIR expecting: failure
+
+public subscript s(x: Int): Int {
+  //! @+1 diagnostic return statement in subscript
+  return x
+}