diff --git a/src/compiler/io/compilerMessage.ml b/src/compiler/io/compilerMessage.ml index b5f13e8529f..259c7b1decd 100644 --- a/src/compiler/io/compilerMessage.ml +++ b/src/compiler/io/compilerMessage.ml @@ -85,11 +85,7 @@ let replay_message com cm = | MKWarning(w, options) -> com.warning ~depth:cm.cm_depth w options cm.cm_message cm.cm_pos | _ -> - let is_diagnostics_only = match cm.cm_diagnostics_kind with - | MessageKind.DKMissingFields | MessageKind.DKUnresolvedIdentifier -> true - | _ -> false - in - if not is_diagnostics_only || is_diagnostics com then + if not (Message.cm_is_diagnostics_only cm) || is_diagnostics com then com.part_scope.messages <- cm :: com.part_scope.messages (* Default handlers *) diff --git a/src/compiler/server/serverCache.ml b/src/compiler/server/serverCache.ml index 116ea9a55b4..4d63075f283 100644 --- a/src/compiler/server/serverCache.ml +++ b/src/compiler/server/serverCache.ml @@ -230,8 +230,21 @@ let check_module sctx com m_path m_extra p = | Some reason -> raise (Dirty (DependencyDirty(mpath,reason))) ) m_extra.m_deps in + (* Errors like missing fields are downgraded to diagnostics-only messages when typing in + diagnostics mode. Such a module cannot be reused by an actual compilation, which has to + type it again in order to produce the real error (#12995). *) + let check_diagnostics_only_errors () = + if not (is_diagnostics com) && DynArray.fold_left (fun acc cbo -> acc || match cbo with + | Message cm -> + Message.cm_is_diagnostics_only cm + | _ -> + false + ) false m_extra.m_cache_bound_objects then + raise (Dirty (Tainted DiagnosticsOnlyErrors)) + in let check () = try + check_diagnostics_only_errors(); check_module_path(); if not (has_policy NoFileSystemCheck) || Path.file_extension (Path.UniqueKey.lazy_path m_extra.m_file) <> "hx" then check_file(); if (get_typing_mode com m_extra) = FullTyping then check_dependencies(); diff --git a/src/context/common.ml b/src/context/common.ml index c34adbfc85e..05acc818566 100644 --- a/src/context/common.ml +++ b/src/context/common.ml @@ -831,9 +831,7 @@ let is_compilation com = com.display.dms_kind = DMNone && not (is_diagnostics co not prevent context caching. *) let has_error_to_report com = let has_reportable_message = List.exists (fun cm -> - match cm.cm_diagnostics_kind with - | MessageKind.DKMissingFields | MessageKind.DKUnresolvedIdentifier -> false - | _ -> true + not (Message.cm_is_diagnostics_only cm) ) com.part_scope.messages in com.part_scope.has_error && (is_compilation com || has_reportable_message) diff --git a/src/core/message.ml b/src/core/message.ml index 381bab21d83..9815da46eec 100644 --- a/src/core/message.ml +++ b/src/core/message.ml @@ -67,6 +67,12 @@ type t = { let cm_severity cm = message_kind_severity cm.cm_message_kind +(** Messages which only exist in diagnostics mode, where the corresponding error is downgraded to + diagnostics data instead of being reported. *) +let cm_is_diagnostics_only cm = match cm.cm_diagnostics_kind with + | MessageKind.DKMissingFields | MessageKind.DKUnresolvedIdentifier -> true + | _ -> false + let cm_code cm = match cm.cm_message_kind with | MKWarning(w,_) -> let wobj = WarningList.warning_obj w in diff --git a/src/core/tPrinting.ml b/src/core/tPrinting.ml index b91205d1d8f..2ac242e2f8e 100644 --- a/src/core/tPrinting.ml +++ b/src/core/tPrinting.ml @@ -651,6 +651,7 @@ module Printer = struct | ServerInvalidate -> "server/invalidate" | ServerInvalidateFiles -> "server_invalidate_files" | ServerInvalidateModule -> "server_invalidate_module" + | DiagnosticsOnlyErrors -> "diagnostics_only_errors" let s_module_skip_reason reason = let rec loop stack = function diff --git a/src/core/tType.ml b/src/core/tType.ml index e7efeec516e..e52db71e6dd 100644 --- a/src/core/tType.ml +++ b/src/core/tType.ml @@ -38,6 +38,7 @@ type module_tainting_reason = | ServerInvalidate | ServerInvalidateFiles | ServerInvalidateModule + | DiagnosticsOnlyErrors type module_skip_reason = | DependencyDirty of path * module_skip_reason diff --git a/tests/server/src/cases/issues/Issue12995.hx b/tests/server/src/cases/issues/Issue12995.hx new file mode 100644 index 00000000000..8591cd97296 --- /dev/null +++ b/tests/server/src/cases/issues/Issue12995.hx @@ -0,0 +1,17 @@ +package cases.issues; + +class Issue12995 extends TestCase { + function test(_) { + vfs.putContent("Main.hx", getTemplate("issues/Issue12995/Main.hx")); + var args = ["-main", "Main"]; + + runHaxe(args); + assertErrorMessage("Class has no field bar"); + + runHaxeJson(args, DisplayMethods.Diagnostics, {file: new FsPath("Main.hx")}); + + // The diagnostics request must not cache the erroring module (#12995) + runHaxe(args); + assertErrorMessage("Class has no field bar"); + } +} diff --git a/tests/server/test/templates/issues/Issue12995/Main.hx b/tests/server/test/templates/issues/Issue12995/Main.hx new file mode 100644 index 00000000000..0dda6517bb7 --- /dev/null +++ b/tests/server/test/templates/issues/Issue12995/Main.hx @@ -0,0 +1,7 @@ +class Foo {} + +class Main { + static function main() { + Foo.bar(); + } +}