Skip to content

Fix changing Taclet Options via the GUI (and more) + TimSort source files added as examples#3889

Merged
unp1 merged 10 commits into
mainfrom
bubel/keyload-error-messages
Jul 4, 2026
Merged

Fix changing Taclet Options via the GUI (and more) + TimSort source files added as examples#3889
unp1 merged 10 commits into
mainfrom
bubel/keyload-error-messages

Conversation

@unp1

@unp1 unp1 commented Jul 4, 2026

Copy link
Copy Markdown
Member

Related Issue

Not related to a specific issue.

These problems were found while resurrecting the TimSort case study; each is a misleading error message or a load/settings bug encountered along the way.

This PR adds error message improvements, the TimSort case study (loads, but some of the shift rules are not yet ported) and most important a bug fix preventing one to change taclet options in the GUI.

Intended Change

A batch of independent fixes that make KeY's problem-loading errors point at the real cause, plus two GUI correctness fixes. Each is a self-contained commit.

Fix that taclet options cannot be changed via the GUI

  • Taclet-option changes are applied when a proof is loaded. With a proof loaded, the Taclet Options panel edited a detached ChoiceSettings copy, so changing e.g. the integer semantics and reloading kept the old option. applySettings now writes through to the global DEFAULT_SETTINGS that a reload reads.

Clearer / correctly-attributed error messages

  • Boot/library stub parse failures are reported at the stub. When a stub under JavaRedux (or a \bootclasspath/\classpath entry) failed to parse, JavaService.parseSpecialClasses had already marked the model as parsed, so the half-built model was silently reused and the first taclet needing a JDK type (e.g. doubleSinjava.lang.Math) reported "java.lang.Math cannot be found" against an unrelated rule file. The flag is now reset on failure and the real parse error (with the offending stub's location) is surfaced.
  • Unresolvable JML operators are readable. JmlTermFactory dumped internal term syntax — Cannot resolve JML operation add(right,left) >>> Z(1(#)) …. It now pretty-prints the operands and states the operator and operand types: Operator '>>>' is not defined for operands of type '\bigint' and 'int' (in 'right + left >>> 1').
  • Spec-math-mode hint for operators. Some operators exist only in certain spec math modes (>>> is defined for int/long but not \bigint). The message now adds: "…not available in the 'spec_bigint_math' spec math mode; it is available under spec_java_math or spec_safe_math", instead of implying a type fix.
  • Missing \classpath/\bootclasspath no longer blames a taclet. A missing directory threw a FileNotFoundException deep in lazy model building, reported as "Could not parse Java block '{..#lhs=+#e;...}'" against a built-in rule file. The underlying IO failure is now surfaced directly.
  • …and it points at its declaration. That error had no source location (dialog showed Line -1 / "[SOURCE COULD NOT BE LOADED]"). The \classpath/\bootclasspath token position is now captured at parse time and validated eagerly (as \javaSource already was), so the message reads "The \classpath entry "…/classpath" does not exist. at …/Sort.key:2:12" and the dialog opens the .key file at the offending line.

GUI correctness

  • "Save, Close and Reload" reloads the problem, not the edited source. The button always reloaded the edited file. This does not work if one is using a .key file with custom classpaths etc. This PR changes the behavior to reload the most recent file after editing.
  • Proof-tree ghost rows after auto mode. The proof was not always repainted after returning from automode. This PR ensures that a repaint happens.

Type of pull request

  • Bug fix (non-breaking change which fixes an issue)
  • There are changes to the (Java) code

Ensuring quality

  • I made sure that introduced/changed code is well documented (javadoc and inline comments).
  • I have tested the feature as follows: manual tests

Additional information and contact(s)

Created with AI tooling support

The contributions within this pull request are licensed under GPLv2 (only) for inclusion in KeY.

unp1 added 9 commits July 4, 2026 02:29
When a stub under JavaRedux (or a \bootclasspath/\classpath entry) fails to
parse, the whole Java model build aborts. This was reported with a misleading
message that blamed an unrelated built-in taclet: the first rule needing a JDK
type (e.g. doubleSin, whose \find embeds java.lang.Math.sin) would report
"java.lang.Math cannot be found" and point at floatRulesAssumeStrictfp.key,
hiding the real parse error in the offending stub.

Two causes:

* JavaService.parseSpecialClasses set the parsedSpecial flag to true *before*
  parsing. On failure the flag stayed true, so the half-built Java model was
  silently marked "done" and reused; every later type lookup then failed with a
  misleading "cannot be found". Reset the flag on failure and let the real
  exception (which carries the offending stub's file:line) propagate.

* ExpressionBuilder.getJavaBlock wrapped every failure as "Could not parse Java
  block ...". When the underlying failure is really a boot/library-class parse
  failure, the modality's Java block is an innocent bystander. Detect that case
  (a BuildingExceptions whose issues point at real .java/.jml stub files) and
  surface it directly, so the error names the stub and its position.

Creted with support of AI tooling
When an overloaded JML operator has no handler for its operand types,
JmlTermFactory.binary/unary reported the failure by dumping KeY's internal
term representation, e.g.

  Cannot resolve JML operation add(right,left) >>> Z(1(#))
    (types (type, sort): (\bigint,int) >>> (type, sort): (int,int)).

The raw terms (add(...), Z(1(#))) and the "(type, sort)" dump are meaningless
to users. Pretty-print the operands via LogicPrinter and state the operator and
operand types plainly:

  Operator '>>>' is not defined for operands of type '\bigint' and 'int'
    (in 'right + left >>> 1').

Creted with support of AI tooling
…d Reload"

The error dialog's "Save, Close and Reload" button (EditSourceFileAction) called
MainWindow.loadProblem(sourceFile), where sourceFile is the file the error
pointed at - typically a .java source reached from a .key problem via \javaSource.

Loading that bare source file re-enters KeY without the original problem's
\includes, so any user-defined symbol declared there vanishes. A spec that is
actually fine then fails on reload with a misleading "Unknown escaped symbol X".

Concretely: load a .key problem that \includes a symbols file and \javaSource-es
a class whose JML uses those symbols; trigger any spec error; hit "Edit File",
change something, "Save, Close and Reload" -> the reload now fails with
"Unknown escaped symbol ..." on a symbol that was defined all along.

Reload the most-recently-opened problem instead (recorded at load start, so it is
still available after a failed load), falling back to the source file only if no
recent problem is known.

Creted with support of AI tooling
Some JML operators are only defined in certain spec math modes: e.g. `>>>` is
implemented for `int`/`long` (in `spec_java_math`/`spec_safe_math`) but not for
`\bigint`, so in the default `spec_bigint_math` it fails no matter how the
operands are cast - the useful advice is to change the mode, not the operands.

The previous message ("Operator '>>>' is not defined for operands of type
'\bigint' and 'int'") wrongly implied a type fix would help. Now, when the
operator is available in another mode, the message says so:

  Operator '>>>' is not defined for operands of type 'int' and 'int' (in 'self.x >>> 1').
  The '>>>' operator is not available in the 'spec_bigint_math' spec math mode;
  it is available under spec_java_math or spec_safe_math (set as a class or method modifier).

IntegerHandler.supportingModes reports which modes define an operator;
OverloadedOperatorHandler.modeHint turns that into the hint; JmlTermFactory
appends it to the binary/unary error messages.

Creted with support of AI tooling
…et's Java block

A missing \classpath or \bootclasspath directory throws a FileNotFoundException
from JavaService while the Java model is being built lazily during taclet
parsing. getJavaBlock caught it and reported "Could not parse Java block
'{..#lhs=+#e;...}'" against a built-in rule file (e.g. integerRulesCommon.key) -
the concrete, correct reason buried as a nested cause.

Extend the environment-setup detection (previously only unwrapped a library
BuildingExceptions) to also surface an IOException in the cause chain, so the
real message is shown directly:

  java.io.FileNotFoundException: The \classpath entry ".../classpath" does not exist.

Creted with support of AI tooling
… the .key file

A missing \classpath/\bootclasspath directory was reported without any source
location: the GUI dialog showed "Line -1 / Column -1" and "[SOURCE COULD NOT BE
LOADED]", so the user could not see which declaration was at fault.

Capture the source position of each \classpath/\bootclasspath value while parsing
the .key file (FindProblemInformation -> ProblemInformation.pathLocations) and
validate the directories' existence eagerly in KeYFile.readClassPath/
readBootClassPath (as readJavaPath already does for \javaSource). The resulting
BuildingException now carries an explicit Location, so the error reads e.g.

  The \classpath entry ".../classpath" does not exist. at .../Sort.key:2:12

and the dialog opens Sort.key at the offending line. Adds a
BuildingException(Location, String) constructor for errors that originate at a
.key declaration rather than an offending parser token.

Creted with support of AI tooling
…aded

Changing a taclet option (e.g. the integer semantics) and reloading kept the old
option. With a proof loaded, SettingsManager.getChoiceSettings hands the Taclet
Options panel a *detached* ChoiceSettings copy initialised from that proof (so
the panel can display the proof's active options). applySettings wrote the edited
choices back into that throwaway copy, so the change never reached
ProofSettings.DEFAULT_SETTINGS - which is exactly what (re)loading a problem reads
to build a new proof (InitConfig.computeDefaults). The edit was silently lost.

Write the applied choices through to the global default settings. Taclet options
are global defaults for new proofs anyway ("Taclet options will take effect only
on new proofs"), so a subsequent reload now builds the proof with the chosen
option. When no proof is loaded the panel already edited the global settings, so
behaviour there is unchanged.

Creted with support of AI tooling
…t rows)

After auto mode, the proof tree caught up with many nodes at once (the model is
set non-attentive during auto mode) and makeNodeVisible scrolled to the current
goal with scrollPathToVisible + validate(). scrollPathToVisible moves the
viewport via its blit scroll mode, and validate() only re-lays-out - it does not
repaint - so the copied region kept stale pixels: ghost / horizontally shifted
rows that only cleared once the user dragged the scrollbar by hand (observed on
both the vertical and horizontal scrollbar).

Repaint the viewport after the programmatic scroll so the final state is drawn
correctly. makeNodeVisible is not on the hot auto-mode path (the model is
non-attentive then), so the extra repaint is cheap.

Creted with support of AI tooling
@unp1 unp1 changed the title Fix GUI taclet-option changes, clearer problem-loading errors, and TimSort case study Fix changing Taclet Options via the GUI (and more) + TimSort source files added as examples Jul 4, 2026
@unp1 unp1 self-assigned this Jul 4, 2026
@unp1 unp1 added 🐞 Bug Error Reporting Missing file/position info for parse errors, uncaught errors, wrong/unclear messages, ... labels Jul 4, 2026
@unp1 unp1 added this to the v3.0.0 milestone Jul 4, 2026
When the proof-tree tab is hidden, the view deliberately stops listening, so a proof disposed meanwhile leaves the JTree holding a model of the disposed proof. On the next model swap, JTree.setModel clears the selection, which makes the tree UI measure -- and thereby render -- the old selection paths, crashing in the renderer on Proof.getServices of the disposed proof. Replace the selection model with a fresh one before installing the new tree model: the stale paths are forgotten without ever being rendered, and no selection events are fired.
@unp1 unp1 enabled auto-merge July 4, 2026 10:08
@unp1 unp1 added this pull request to the merge queue Jul 4, 2026
Merged via the queue into main with commit b649c2a Jul 4, 2026
36 checks passed
@unp1 unp1 deleted the bubel/keyload-error-messages branch July 4, 2026 15:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Error Reporting Missing file/position info for parse errors, uncaught errors, wrong/unclear messages, ... 🐞 Bug

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants