Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(compiler): Ignore compiler warnings #2142

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions cli/bin/grain.js
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,12 @@ class GrainCommand extends commander.Command {
"--verbose",
"print critical information at various stages of compilation"
);
cmd.forwardOption(
"--ignore-warnings <warnings>",
"compiler warnings to ignore",
list,
[]
);
return cmd;
}
}
Expand Down
55 changes: 55 additions & 0 deletions compiler/src/utils/config.re
Original file line number Diff line number Diff line change
Expand Up @@ -398,6 +398,61 @@ let import_memory =
false,
);

type ignore_warning =
| IgnoreAll
| LetRecNonFunction
| AmbiguousName
| StatementType
| NonreturningStatement
| AllClausesGuarded
| PartialMatch
| UnusedMatch
| UnusedPat
| NonClosedRecordPattern
| UnreachableCase
| ShadowConstructor
| NoCmiFile
| FuncWasmUnsafe
| FromNumberLiteral
| UselessRecordSpread
| PrintUnsafe
| ToStringUnsafe
| ArrayIndexNonInteger;

let ignore_warnings =
opt(
~names=["ignore-warnings"],
~conv=
Cmdliner.Arg.(
list(
enum([
("all", IgnoreAll),
("letRecNonFunction", LetRecNonFunction),
("ambiguousName", AmbiguousName),
("statementType", StatementType),
("nonreturningStatement", NonreturningStatement),
("allClausesGuarded", AllClausesGuarded),
("partialMatch", PartialMatch),
("unusedMatch", UnusedMatch),
("unusedPat", UnusedPat),
("nonClosedRecordPattern", NonClosedRecordPattern),
("unreachableCase", UnreachableCase),
("shadowConstructor", ShadowConstructor),
("noCmiFile", NoCmiFile),
("funcWasmUnsafe", FuncWasmUnsafe),
("fromNumberLiteral", FromNumberLiteral),
("uselessRecordSpread", UselessRecordSpread),
("printUnsafe", PrintUnsafe),
("toStringUnsafe", ToStringUnsafe),
("arrayIndexNonInteger", ArrayIndexNonInteger),
]),
)
),
~doc="Compiler warnings to ignore",
~digestible=NotDigestible,
[],
);

type compilation_mode =
| Normal /* Standard compilation with regular bells and whistles */
| Runtime /* GC doesn't exist yet, allocations happen in runtime heap */;
Expand Down
25 changes: 25 additions & 0 deletions compiler/src/utils/config.rei
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,27 @@ type compilation_mode =
| Normal /* Standard compilation with regular bells and whistles */
| Runtime /* GC doesn't exist yet, allocations happen in runtime heap */;

type ignore_warning =
| IgnoreAll
| LetRecNonFunction
| AmbiguousName
| StatementType
| NonreturningStatement
| AllClausesGuarded
| PartialMatch
| UnusedMatch
| UnusedPat
| NonClosedRecordPattern
| UnreachableCase
| ShadowConstructor
| NoCmiFile
| FuncWasmUnsafe
| FromNumberLiteral
| UselessRecordSpread
| PrintUnsafe
| ToStringUnsafe
| ArrayIndexNonInteger;

/** The Grain stdlib directory, based on the current configuration */
let stdlib_directory: unit => option(string);

Expand Down Expand Up @@ -82,6 +103,10 @@ let maximum_memory_pages: ref(option(int));

let import_memory: ref(bool);

/** Compiler warnings to ignore */

let ignore_warnings: ref(list(ignore_warning));

/** Whether this module should be compiled in runtime mode */

let compilation_mode: ref(compilation_mode);
Expand Down
39 changes: 36 additions & 3 deletions compiler/src/utils/warnings.re
Original file line number Diff line number Diff line change
Expand Up @@ -167,9 +167,9 @@ let message =
}
| UselessRecordSpread => "this record spread is useless as all of the record's fields are overridden."
| PrintUnsafe(typ) =>
"it looks like you are using `print` on an unsafe Wasm value here.\nThis is generally unsafe and will cause errors. Use `DebugPrint.print`"
"it looks like you are using `print` on an unsafe Wasm value here.\nThis is generally unsafe and will cause errors. Use `DebugPrint.print"
++ typ
++ " from the `runtime/debugPrint` module instead."
++ "` from the `runtime/debugPrint` module instead."
| ToStringUnsafe(typ) =>
"it looks like you are using `toString` on an unsafe Wasm value here.\nThis is generally unsafe and will cause errors. Use `DebugPrint.toString`"
++ typ
Expand All @@ -196,7 +196,40 @@ let backup = () => current^;

let restore = x => current := x;

let is_active = x => current^.active[number(x)];
let ignore_warning = warning => {
let config_warning =
switch (warning) {
| LetRecNonFunction(_) => Some(Config.LetRecNonFunction)
| AmbiguousName(_) => Some(Config.AmbiguousName)
| StatementType => Some(Config.StatementType)
| NonreturningStatement => Some(Config.NonreturningStatement)
| AllClausesGuarded => Some(Config.AllClausesGuarded)
| PartialMatch(_) => Some(Config.PartialMatch)
| UnusedMatch => Some(Config.UnusedMatch)
| UnusedPat => Some(Config.UnusedPat)
| NonClosedRecordPattern(_) => Some(Config.NonClosedRecordPattern)
| UnreachableCase => Some(Config.UnreachableCase)
| ShadowConstructor(_) => Some(Config.ShadowConstructor)
| NoCmiFile(_) => Some(Config.NoCmiFile)
| FuncWasmUnsafe(_) => Some(Config.FuncWasmUnsafe)
| FromNumberLiteral(_) => Some(Config.FromNumberLiteral)
| UselessRecordSpread => Some(Config.UselessRecordSpread)
| PrintUnsafe(_) => Some(Config.PrintUnsafe)
| ToStringUnsafe(_) => Some(Config.ToStringUnsafe)
| ArrayIndexNonInteger(_) => Some(Config.ArrayIndexNonInteger)
// TODO(#681): Look into reenabling these
| NotPrincipal(_)
| NameOutOfScope(_)
| FragileMatch(_)
| UnusedExtension => None
};

List.mem(Config.IgnoreAll, Config.ignore_warnings^)
|| Option.map(x => List.mem(x, Config.ignore_warnings^), config_warning)
|> Option.value(~default=false);
};

let is_active = x => current^.active[number(x)] && !ignore_warning(x);
let is_error = x => current^.error[number(x)];

let nerrors = ref(0);
Expand Down
9 changes: 5 additions & 4 deletions compiler/test/runner.re
Original file line number Diff line number Diff line change
Expand Up @@ -269,21 +269,22 @@ let makeCompileErrorRunner =
};

let makeWarningRunner =
(test, ~module_header=module_header, name, prog, warning) => {
(test, ~config_fn=?, ~module_header=module_header, name, prog, warning) => {
test(name, ({expect}) => {
Config.preserve_all_configs(() => {
Config.print_warnings := false;
ignore @@ compile(name, module_header ++ prog);
ignore @@ compile(name, ~config_fn?, module_header ++ prog);
expect.ext.warning.toHaveTriggered(warning);
})
});
};

let makeNoWarningRunner = (test, ~module_header=module_header, name, prog) => {
let makeNoWarningRunner =
(test, ~config_fn=?, ~module_header=module_header, name, prog) => {
test(name, ({expect}) => {
Config.preserve_all_configs(() => {
Config.print_warnings := false;
ignore @@ compile(name, module_header ++ prog);
ignore @@ compile(name, ~config_fn?, module_header ++ prog);
expect.ext.warning.toHaveTriggeredNoWarnings();
})
});
Expand Down
72 changes: 72 additions & 0 deletions compiler/test/suites/ignore_warnings.re
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
open Grain_tests.TestFramework;
open Grain_tests.Runner;
open Grain_utils;

let {describe} =
describeConfig |> withCustomMatchers(customMatchers) |> build;

describe("ignore warnings", ({test, testSkip}) => {
let assertWarning = makeWarningRunner(test);
let assertNoWarning = makeNoWarningRunner(test);

let assertWarningFlag = (name, code, config_warning, expected_warning) => {
assertWarning(
~config_fn=() => {Config.ignore_warnings := []},
name,
code,
expected_warning,
);

assertNoWarning(
~config_fn=() => {Config.ignore_warnings := [config_warning]},
name,
code,
);
};

assertWarningFlag(
"warning_match",
{|
match (true) {
true => void
}
|},
Config.PartialMatch,
Warnings.PartialMatch("false"),
);

assertWarningFlag(
"warning_match_all_ignored",
{|
match (true) {
true => void
}
|},
Config.IgnoreAll,
Warnings.PartialMatch("false"),
);

assertWarningFlag(
"warning_useless_record_spread",
{|
record R { x: Number }
let r = { x: 1 }
let r2 = { ...r, x: 2 }
|},
Config.UselessRecordSpread,
Warnings.UselessRecordSpread,
);

assertWarningFlag(
"warning_print_unsafe",
{|
@unsafe
let f = () => {
let a = 1n
print(a)
}
|},
Config.PrintUnsafe,
Warnings.PrintUnsafe("I32"),
);
});
Loading