WARNING: THIS SITE IS A MIRROR OF GITHUB.COM / IT CANNOT LOGIN OR REGISTER ACCOUNTS / THE CONTENTS ARE PROVIDED AS-IS / THIS SITE ASSUMES NO RESPONSIBILITY FOR ANY DISPLAYED CONTENT OR LINKS / IF YOU FOUND SOMETHING MAY NOT GOOD FOR EVERYONE, CONTACT ADMIN AT ilovescratch@foxmail.com
Skip to content

Commit 82abed4

Browse files
authored
Support GHC 9.10, 9.12 (#358)
Needs #344
1 parent 964153b commit 82abed4

File tree

7 files changed

+205
-26
lines changed

7 files changed

+205
-26
lines changed

flake.nix

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,8 @@
7575
ghcVersions = [
7676
"ghc96"
7777
"ghc98"
78+
"ghc910"
79+
"ghc912"
7880
];
7981
in {
8082
_pkgs = eachSystem (localSystem: makePkgs {inherit localSystem;});

src/ghci/error_log.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ use tokio::io::BufWriter;
66
use tracing::instrument;
77

88
use super::parse::CompilationResult;
9+
use super::parse::ModulesLoaded;
910
use super::CompilationLog;
1011

1112
/// Error log writer.
@@ -40,7 +41,7 @@ impl ErrorLog {
4041
// `ghcid` only writes the headline if there's no errors.
4142
if let CompilationResult::Ok = summary.result {
4243
tracing::debug!(%path, "Writing 'All good'");
43-
let modules_loaded = if summary.modules_loaded != 1 {
44+
let modules_loaded = if summary.modules_loaded != ModulesLoaded::Count(1) {
4445
format!("{} modules", summary.modules_loaded)
4546
} else {
4647
format!("{} module", summary.modules_loaded)

src/ghci/parse/ghc_message/compilation_summary.rs

Lines changed: 124 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
use std::fmt::Display;
2+
13
use winnow::ascii::digit1;
24
use winnow::combinator::alt;
35
use winnow::combinator::opt;
@@ -23,10 +25,31 @@ pub struct CompilationSummary {
2325
/// The compilation result; whether compilation succeeded or failed.
2426
pub result: CompilationResult,
2527
/// The count of modules loaded.
26-
pub modules_loaded: usize,
28+
pub modules_loaded: ModulesLoaded,
29+
}
30+
31+
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
32+
pub enum ModulesLoaded {
33+
/// The count of modules loaded.
34+
Count(usize),
35+
/// All modules were loaded, unknown count.
36+
All,
37+
}
38+
39+
impl Display for ModulesLoaded {
40+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
41+
match self {
42+
ModulesLoaded::Count(n) => write!(f, "{n}"),
43+
ModulesLoaded::All => write!(f, "all"),
44+
}
45+
}
2746
}
2847

2948
/// Parse a compilation summary, like `Ok, one module loaded.`.
49+
///
50+
/// NB: This will definitely explode if you have `Opt_ShowLoadedModules` enabled.
51+
///
52+
/// See: <https://gitlab.haskell.org/ghc/ghc/-/blob/6d779c0fab30c39475aef50d39064ed67ce839d7/ghc/GHCi/UI.hs#L2309-L2329>
3053
pub fn compilation_summary(input: &mut &str) -> PResult<CompilationSummary> {
3154
let result = alt((
3255
"Ok".map(|_| CompilationResult::Ok),
@@ -35,6 +58,33 @@ pub fn compilation_summary(input: &mut &str) -> PResult<CompilationSummary> {
3558
.parse_next(input)?;
3659
let _ = ", ".parse_next(input)?;
3760

61+
let modules_loaded = alt((
62+
compilation_summary_no_modules,
63+
compilation_summary_unloaded_all,
64+
compilation_summary_count,
65+
))
66+
.parse_next(input)?;
67+
68+
let _ = '.'.parse_next(input)?;
69+
let _ = line_ending_or_eof.parse_next(input)?;
70+
71+
Ok(CompilationSummary {
72+
result,
73+
modules_loaded,
74+
})
75+
}
76+
77+
fn compilation_summary_no_modules(input: &mut &str) -> PResult<ModulesLoaded> {
78+
let _ = "no modules to be reloaded".parse_next(input)?;
79+
Ok(ModulesLoaded::Count(0))
80+
}
81+
82+
fn compilation_summary_unloaded_all(input: &mut &str) -> PResult<ModulesLoaded> {
83+
let _ = "unloaded all modules".parse_next(input)?;
84+
Ok(ModulesLoaded::All)
85+
}
86+
87+
fn compilation_summary_count(input: &mut &str) -> PResult<ModulesLoaded> {
3888
// There's special cases for 0-6 modules!
3989
// https://gitlab.haskell.org/ghc/ghc/-/blob/288235bbe5a59b8a1bda80aaacd59e5717417726/ghc/GHCi/UI.hs#L2286-L2287
4090
// https://gitlab.haskell.org/ghc/ghc/-/blob/288235bbe5a59b8a1bda80aaacd59e5717417726/compiler/GHC/Utils/Outputable.hs#L1429-L1453
@@ -51,13 +101,10 @@ pub fn compilation_summary(input: &mut &str) -> PResult<CompilationSummary> {
51101
.parse_next(input)?;
52102
let _ = " module".parse_next(input)?;
53103
let _ = opt("s").parse_next(input)?;
54-
let _ = " loaded.".parse_next(input)?;
55-
let _ = line_ending_or_eof.parse_next(input)?;
104+
let _ = ' '.parse_next(input)?;
105+
let _ = alt(("loaded", "reloaded", "added", "unadded", "checked")).parse_next(input)?;
56106

57-
Ok(CompilationSummary {
58-
result,
59-
modules_loaded,
60-
})
107+
Ok(ModulesLoaded::Count(modules_loaded))
61108
}
62109

63110
#[cfg(test)]
@@ -75,7 +122,7 @@ mod tests {
75122
.unwrap(),
76123
CompilationSummary {
77124
result: CompilationResult::Ok,
78-
modules_loaded: 123,
125+
modules_loaded: ModulesLoaded::Count(123),
79126
}
80127
);
81128

@@ -85,7 +132,7 @@ mod tests {
85132
.unwrap(),
86133
CompilationSummary {
87134
result: CompilationResult::Ok,
88-
modules_loaded: 0,
135+
modules_loaded: ModulesLoaded::Count(0),
89136
}
90137
);
91138

@@ -95,7 +142,7 @@ mod tests {
95142
.unwrap(),
96143
CompilationSummary {
97144
result: CompilationResult::Ok,
98-
modules_loaded: 1,
145+
modules_loaded: ModulesLoaded::Count(1),
99146
}
100147
);
101148

@@ -105,7 +152,7 @@ mod tests {
105152
.unwrap(),
106153
CompilationSummary {
107154
result: CompilationResult::Ok,
108-
modules_loaded: 6,
155+
modules_loaded: ModulesLoaded::Count(6),
109156
}
110157
);
111158

@@ -115,7 +162,7 @@ mod tests {
115162
.unwrap(),
116163
CompilationSummary {
117164
result: CompilationResult::Err,
118-
modules_loaded: 7,
165+
modules_loaded: ModulesLoaded::Count(7)
119166
}
120167
);
121168

@@ -125,7 +172,71 @@ mod tests {
125172
.unwrap(),
126173
CompilationSummary {
127174
result: CompilationResult::Err,
128-
modules_loaded: 1,
175+
modules_loaded: ModulesLoaded::Count(1),
176+
}
177+
);
178+
179+
// Other verbs.
180+
assert_eq!(
181+
compilation_summary
182+
.parse("Ok, 10 modules reloaded.\n")
183+
.unwrap(),
184+
CompilationSummary {
185+
result: CompilationResult::Ok,
186+
modules_loaded: ModulesLoaded::Count(10),
187+
}
188+
);
189+
190+
assert_eq!(
191+
compilation_summary
192+
.parse("Ok, 10 modules added.\n")
193+
.unwrap(),
194+
CompilationSummary {
195+
result: CompilationResult::Ok,
196+
modules_loaded: ModulesLoaded::Count(10),
197+
}
198+
);
199+
200+
assert_eq!(
201+
compilation_summary
202+
.parse("Ok, 10 modules unadded.\n")
203+
.unwrap(),
204+
CompilationSummary {
205+
result: CompilationResult::Ok,
206+
modules_loaded: ModulesLoaded::Count(10),
207+
}
208+
);
209+
210+
assert_eq!(
211+
compilation_summary
212+
.parse("Ok, 10 modules checked.\n")
213+
.unwrap(),
214+
CompilationSummary {
215+
result: CompilationResult::Ok,
216+
modules_loaded: ModulesLoaded::Count(10),
217+
}
218+
);
219+
220+
// Special cases!
221+
assert_eq!(
222+
compilation_summary
223+
.parse("Ok, no modules to be reloaded.\n")
224+
.unwrap(),
225+
CompilationSummary {
226+
result: CompilationResult::Ok,
227+
modules_loaded: ModulesLoaded::Count(0),
228+
}
229+
);
230+
231+
// Literally just for the 'unloaded' message. You can definitely reload all modules too,
232+
// but whatever.
233+
assert_eq!(
234+
compilation_summary
235+
.parse("Ok, unloaded all modules.\n")
236+
.unwrap(),
237+
CompilationSummary {
238+
result: CompilationResult::Ok,
239+
modules_loaded: ModulesLoaded::All,
129240
}
130241
);
131242

src/ghci/parse/ghc_message/mod.rs

Lines changed: 60 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ mod message_body;
2727
mod compilation_summary;
2828
use compilation_summary::compilation_summary;
2929
pub use compilation_summary::CompilationSummary;
30+
pub use compilation_summary::ModulesLoaded;
3031

3132
mod loaded_configuration;
3233
use loaded_configuration::loaded_configuration;
@@ -267,9 +268,67 @@ mod tests {
267268
}),
268269
GhcMessage::Summary(CompilationSummary {
269270
result: CompilationResult::Err,
270-
modules_loaded: 1,
271+
modules_loaded: ModulesLoaded::Count(1),
271272
}),
272273
]
273274
);
274275
}
276+
277+
#[test]
278+
fn test_parse_messages_ghc910() {
279+
assert_eq!(
280+
parse_ghc_messages(indoc!(
281+
r#"
282+
[2 of 3] Compiling MyModule ( src/MyModule.hs, interpreted ) [Source file changed]
283+
284+
src/MyModule.hs:4:11: error: [GHC-83865]
285+
• Couldn't match type ‘[Char]’ with ‘()’
286+
Expected: ()
287+
Actual: String
288+
• In the expression: "example"
289+
In an equation for ‘example’: example = "example"
290+
|
291+
4 | example = "example"
292+
| ^^^^^^^^^
293+
Failed, two modules loaded.
294+
"#
295+
))
296+
.unwrap(),
297+
vec![
298+
GhcMessage::Compiling(
299+
CompilingModule {
300+
name: "MyModule".into(),
301+
path: "src/MyModule.hs".into(),
302+
},
303+
),
304+
GhcMessage::Diagnostic(
305+
GhcDiagnostic {
306+
severity: Severity::Error,
307+
path: Some(
308+
"src/MyModule.hs".into(),
309+
),
310+
span: PositionRange::new(4, 11, 4, 11),
311+
message: [
312+
"[GHC-83865]",
313+
" • Couldn't match type ‘[Char]’ with ‘()’",
314+
" Expected: ()",
315+
" Actual: String",
316+
" • In the expression: \"example\"",
317+
" In an equation for ‘example’: example = \"example\"",
318+
" |",
319+
"4 | example = \"example\"",
320+
" | ^^^^^^^^^",
321+
""
322+
].join("\n"),
323+
},
324+
),
325+
GhcMessage::Summary(
326+
CompilationSummary {
327+
result: CompilationResult::Err,
328+
modules_loaded: ModulesLoaded::Count(2),
329+
},
330+
),
331+
]
332+
);
333+
}
275334
}

src/ghci/parse/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ pub use ghc_message::CompilationResult;
1919
pub use ghc_message::CompilationSummary;
2020
pub use ghc_message::GhcDiagnostic;
2121
pub use ghc_message::GhcMessage;
22+
pub use ghc_message::ModulesLoaded;
2223
pub use ghc_message::Severity;
2324
pub use module_and_files::CompilingModule;
2425
pub use show_paths::parse_show_paths;

test-harness/src/ghc_version.rs

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -33,16 +33,16 @@ impl Display for FullGhcVersion {
3333
/// Variants of this enum will correspond to `ghcVersions` in `../../flake.nix`.
3434
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
3535
pub enum GhcVersion {
36-
/// GHC 9.0
37-
Ghc90,
38-
/// GHC 9.2
39-
Ghc92,
4036
/// GHC 9.4
4137
Ghc94,
4238
/// GHC 9.6
4339
Ghc96,
4440
/// GHC 9.8
4541
Ghc98,
42+
/// GHC 9.10
43+
Ghc910,
44+
/// GHC 9.12
45+
Ghc912,
4646
}
4747

4848
fn ghc_version_re() -> &'static Regex {
@@ -61,13 +61,18 @@ impl FromStr for GhcVersion {
6161
let (_full, [major, minor, _patch]) = captures.extract();
6262

6363
match (major, minor) {
64-
("9", "0") => Ok(Self::Ghc90),
65-
("9", "2") => Ok(Self::Ghc92),
6664
("9", "4") => Ok(Self::Ghc94),
6765
("9", "6") => Ok(Self::Ghc96),
6866
("9", "8") => Ok(Self::Ghc98),
67+
("9", "10") => Ok(Self::Ghc910),
68+
("9", "12") => Ok(Self::Ghc912),
6969
(_, _) => Err(miette!(
70-
"Only GHC versions 9.0, 9.2, 9.4, 9.6, and 9.8 are supported"
70+
"Only the following GHC versions are supported:\n\
71+
- 9.4\n\
72+
- 9.6\n\
73+
- 9.8\n\
74+
- 9.10\n\
75+
- 9.12"
7176
)),
7277
}
7378
}
@@ -79,10 +84,10 @@ mod tests {
7984

8085
#[test]
8186
fn test_parse_ghc_version() {
82-
assert_eq!("9.0.2".parse::<GhcVersion>().unwrap(), GhcVersion::Ghc90);
83-
assert_eq!("9.2.4".parse::<GhcVersion>().unwrap(), GhcVersion::Ghc92);
8487
assert_eq!("9.4.8".parse::<GhcVersion>().unwrap(), GhcVersion::Ghc94);
8588
assert_eq!("9.6.1".parse::<GhcVersion>().unwrap(), GhcVersion::Ghc96);
89+
assert_eq!("9.10.1".parse::<GhcVersion>().unwrap(), GhcVersion::Ghc910);
90+
assert_eq!("9.12.1".parse::<GhcVersion>().unwrap(), GhcVersion::Ghc910);
8691

8792
"9.6.1rc1"
8893
.parse::<GhcVersion>()

tests/error_log.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ async fn can_write_error_log_compilation_errors() {
8585
.expect("ghciwatch writes ghcid.txt");
8686

8787
let expected = match session.ghc_version() {
88-
Ghc90 | Ghc92 | Ghc94 => expect![[r#"
88+
Ghc94 => expect![[r#"
8989
src/My/Module.hs:3:11: error:
9090
* Couldn't match type `[Char]' with `()'
9191
Expected: ()
@@ -96,7 +96,7 @@ async fn can_write_error_log_compilation_errors() {
9696
3 | myIdent = "Uh oh!"
9797
| ^^^^^^^^
9898
"#]],
99-
Ghc96 | Ghc98 => expect![[r#"
99+
Ghc96 | Ghc98 | Ghc910 | Ghc912 => expect![[r#"
100100
src/My/Module.hs:3:11: error: [GHC-83865]
101101
* Couldn't match type `[Char]' with `()'
102102
Expected: ()

0 commit comments

Comments
 (0)