Repository: hylo-lang/hylo (swift)

Issue:
error: HardFailure: HardFailure()
This is low-priority, but I'm guessing the title string shouldn't show up in diagnostics.  Reproduce with:
```
typealias X: Y = Z
```

Pull request description:
Fixes #1230

Patch:
diff --git a/Sources/FrontEnd/Parse/Parser+Diagnostics.swift b/Sources/FrontEnd/Parse/Parser+Diagnostics.swift
index c746de0b0..df7ad638b 100644
--- a/Sources/FrontEnd/Parse/Parser+Diagnostics.swift
+++ b/Sources/FrontEnd/Parse/Parser+Diagnostics.swift
@@ -116,4 +116,8 @@ extension Diagnostic {
     .error("'\(e.value)'-parameter cannot be implicit", at: e.site)
   }
 
+  static func error(declarationRequiresDefinitionAt site: SourceRange) -> Diagnostic {
+    .error("declaration requires definition", at: site)
+  }
+
 }
diff --git a/Sources/FrontEnd/Parse/Parser.swift b/Sources/FrontEnd/Parse/Parser.swift
index d9be4067e..f1390cca8 100644
--- a/Sources/FrontEnd/Parse/Parser.swift
+++ b/Sources/FrontEnd/Parse/Parser.swift
@@ -1030,12 +1030,16 @@ public enum Parser {
     in state: inout ParserState
   ) throws -> TypeAliasDecl.ID? {
     // Parse the parts of the declaration.
-    let parser =
-      (take(.typealias).and(take(.name))
-        .and(maybe(genericClause))
-        .and(take(.assign))
-        .and(expr))
-    guard let parts = try parser.parse(&state) else { return nil }
+    guard let introducer = state.take(.typealias) else { return nil }
+
+    let n = try state.token(state.expect("identifier", using: { $0.take(.name) }))
+    let g = try genericClause.parse(&state)
+    guard state.take(.assign) != nil else {
+      state.skipUntilNextDecl()
+      let d = Diagnostic.error(declarationRequiresDefinitionAt: .empty(at: state.currentLocation))
+      throw [d] as DiagnosticSet
+    }
+    let e = try state.expect("type expression", using: parseExpr(in:))
 
     // Type alias declarations shall not have attributes.
     if !prologue.attributes.isEmpty {
@@ -1051,11 +1055,11 @@ public enum Parser {
     // Create a new `TypeAliasDecl`.
     return state.insert(
       TypeAliasDecl(
-        introducerSite: parts.0.0.0.0.site,
+        introducerSite: introducer.site,
         accessModifier: declAccessModifier(ofDeclPrologue: prologue, in: &state),
-        identifier: state.token(parts.0.0.0.1),
-        genericClause: parts.0.0.1,
-        aliasedType: parts.1,
+        identifier: n,
+        genericClause: g,
+        aliasedType: e,
         site: state.range(from: prologue.startIndex)))
   }
 
diff --git a/Sources/FrontEnd/Parse/ParserState.swift b/Sources/FrontEnd/Parse/ParserState.swift
index da0c7f97b..4a1161271 100644
--- a/Sources/FrontEnd/Parse/ParserState.swift
+++ b/Sources/FrontEnd/Parse/ParserState.swift
@@ -308,6 +308,11 @@ struct ParserState {
     while take(if: predicate) != nil {}
   }
 
+  /// Consumes tokens until the first one that may be at the start of a declaration.
+  mutating func skipUntilNextDecl() {
+    skip(while: { (next) in !next.mayBeginDecl })
+  }
+
   /// Inserts `n` into `self.ast`, accumulating any diagnostics in `self.diagnostics`.
   mutating func insert<T: Node>(_ n: T) -> T.ID {
     ast.insert(n, diagnostics: &diagnostics)


Test patch:
diff --git a/Tests/HyloTests/TestCases/Parsing/IllegalTypealias.hylo b/Tests/HyloTests/TestCases/Parsing/IllegalTypealias.hylo
new file mode 100644
index 000000000..eea5e2c28
--- /dev/null
+++ b/Tests/HyloTests/TestCases/Parsing/IllegalTypealias.hylo
@@ -0,0 +1,4 @@
+//- parse expecting: failure
+
+//! @+1 diagnostic declaration requires definition
+typealias X: Y = Z