Skip to content

Conversation

@WojciechMazur
Copy link
Contributor

@WojciechMazur WojciechMazur commented Dec 11, 2025

Resolves #24720

All identified error codes produced by compiler are now documented in the reference docs.

  • ~ 200/222 error now have a snippet that show in what circumstances given error might be reported, including the detailed output from the compiler (using -explain), and examples how to fix given problem.
  • The inactive error codes contain description, but are not provided with examples
  • ~10 active error codes have non-compiling examples - this might require specific setup, eg. for too large implicit search scope, or classpath related issues
  • all error codes are validated by running dedicated test-suite:
scala -S 3.nightly test --with-compiler project/scripts/checkErrorCodeSnippets.test.scala  -- +a +l +c

It validates that all error codes (unless explicitlly excluded) are well defined: has example snippet, output errors and solutions. This might also check for additional attributes, eg. :

  • until tag for inactive codes containg the last version when given error code was emmited
  • since tag for code introduced after 3.0.0 - first stable version when given error is emmited
  • created to dedicated tool to manually verify documentation and optionally update the outputs from the failing snippet
 scala -S 3.nightly project/scripts/checkErrorCodeSnippets.scala --with-compiler -- <path to error-code.md> --verbose --update-output
  • create a tool to update all error codes (useful for larger changes regarding reporting error codes):
scala -S 3.nightly project/scripts/checkErrorCodeSnippets.scala --with-compiler --main-class=updateAllErrorCodeOutputs 
  • Each of the scripts uses scala3-compiler, this allows to test changes for manually published versions of the compiler, by providing explicit -S <version we can test against any version of the compiler, including locally published ones.
  • CI now uses these scripts to ensure error codes documentation is consistent
Piggy backs fixes that would be required to have correct assertions in generated scaladoc (would be most likelly cherry-picked before merge): - allow to specific `sc-opts:*` to pass specify scalacOptions that would be passed to the snippetCompiler - show position of snippets that failed to compile

The changes above were extracted to #24755

Piggy backed changes:

  • During documentation of error codes several inactive (not used, or never instantiated) errors were found - these were marked as inactive.
  • scaladoc/generateReferenceDocumentation started to crash after addition of first Markdown snippet - it was caused by classpath/scaladoc setting issue. The problem was fixed, by removing no longer required __fake__.scala file which was used in Scala 3.1 and earlier to workaround requirement of having at least 1 Scala source.

Documentation itself was generated using LLM agents and requires manual review - mostly for correctness of descriptions, code snippets itself are validated to produce correct error codes unless marked with sc:nocompile (see list of non-reproductible error codes in created tool).
Here's the gist with context used to instrument agents

@WojciechMazur
Copy link
Contributor Author

Rendered examples:
image
image

@bishabosha
Copy link
Member

is there an automated process to check for addition of new error codes?

@WojciechMazur
Copy link
Contributor Author

is there an automated process to check for addition of new error codes?

Not yet but I'll add one

@tgodzik
Copy link
Contributor

tgodzik commented Dec 12, 2025

We could also link to these pages from DiagnosticRelatedInformation, it's available in the sbt interfaces.

@tgodzik
Copy link
Contributor

tgodzik commented Dec 12, 2025

Ach, no that would have to be another field, which is not exposed here :/

@tgodzik
Copy link
Contributor

tgodzik commented Dec 12, 2025

We could anyway link the codes in metals automatically once this is merged, which will work on all Scala 3 versions

WojciechMazur added a commit that referenced this pull request Dec 15, 2025
#24755)

Extracted from #24734  
Adds support for `sc-opts:` attribute that can be set in Markdown code
snippets, allowing to pass additioanl arguments to snippet compiler.
This would allow us in #24734 to correctlly document behaviour of
snippets producing error codes that require additional compiler options
to be activated.

Example: ensure that `-Werror` makes given code to actually fail which
can be checked with `sc:fail`,

```
 ```scala sc:fail sc-opts:-Werror,-explain
def exampleShouldError(input: Option[String]): Unit = 
  input match
    case Some("foo") => ???   
```.
```
@WojciechMazur WojciechMazur marked this pull request as ready for review December 15, 2025 19:00
on any expected exceptions. For example:

```scala
try {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we recoment braceless syntax in these snippets?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Most of example for other error codes use bracless syntax, I can adjust this one.

```

It is recommended to use the `NonFatal` extractor to catch all exceptions as it
correctly handles transfer functions like `return`.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Might need an example? What is transfer function?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No idea, example and description was generated based on -explain description from compiler.
So in fact here we have a duplication, the same example in explain and in description (altough outputs are allowed to change any moment)

@WojciechMazur
Copy link
Contributor Author

Review recommendation - here's the list of error codes that are not tested in snippets:

object NonReproducibleErrorCodes:
  val codes: Set[Int] = Set(
    25, // E025: IdentifierExpectedID - triggered by parser in specific contexts, needs investigation
    27, // E027: VarArgsParamMustComeLastID - triggered when varargs not last, needs correct syntax
    28, // E028: IllegalLiteralID - triggered by invalid literals, needs investigation
    33, // E033: PkgDuplicateSymbolID - requires package statements (not compatible with Scaladoc snippets)
    47, // E047: CyclicReferenceInvolvingImplicitID - triggered by implicit cycles, needs investigation
    98, // E098: FailureToEliminateExistential - only triggers when reading Scala 2 classfiles with existential types
    103, // E103: IllegalStartOfStatementID - requires top-level code (not compatible with Scaladoc snippets)
    105, // E105: TraitRedefinedFinalMethodFromAnyRefID - message class exists but never instantiated
    106, // E106: PackageNameAlreadyDefinedID - triggers in incremental compilation with classfile conflicts
    111, // E111: BadSymbolicReferenceID - requires missing classfiles on classpath
    113, // E113: SymbolHasUnparsableVersionNumberID - requires @migration annotation with invalid version
    114, // E114: SymbolChangedSemanticsInVersionID - requires @migration annotation with specific conditions
    138, // E138: TraitParameterUsedAsParentPrefixID - caught earlier by PostTyper with different message
    143, // E143: ErasedTypesCanOnlyBeFunctionTypesID - hard to reproduce,
    152 // E152: ExtensionCanOnlyHaveDefsID - never emitted
  )

These error code are most likely to be invalid, as we couldn't create an exmaple of code snippet which would produce them.

Additional care should be taken against inactive error codes (based on definitions in ErrorMessageId, or by listing error-codes having until argument) - these don't have a testing code snippet as well.
Looking at the file, here are all the inactive error codes (those with isActive = false):

Error Number Error Code Name
0 EmptyCatchOrFinallyBlockID
10 TopLevelImplicitClassID
14 TupleTooLongID
36 DanglingThisInPathID
54 ParameterizedTypeLacksArgumentsID
61 TopLevelCantBeImplicitID
79 OnlyCaseClassOrCaseObjectAllowedID
80 ExpectedTopLevelDefID
85 FunctionTypeNeedsNonEmptyParameterListID
94 EnumCaseDefinitionInNonEnumOwnerID
105 TraitRedefinedFinalMethodFromAnyRefID
142 SkolemInInferredID
150 NoExtensionMethodAllowedID
151 ExtensionMethodCannotHaveTypeParamsID
152 ExtensionCanOnlyHaveDefsID
155 TypeSpliceInValPatternID
163 OverrideTypeMismatchErrorID
196 ContextBoundCompanionNotValueID

Total: 18 inactive error codes

Or other code snippets are validated to ensure that it's possible to produce a described error code.

Some additional care can be also made towards Solutions sections, these are validated to compile, but example might the resulting semantics might be different then example, failing to compile, code


This error is emitted when an expression has a different type than what is expected in that context.

The compiler found an expression of one type where a different type was expected.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems to repeat the information above.


This error is emitted when trying to access a member (method, field, or type) that does not exist on the given type.

The compiler cannot find a member with the specified name on the given type.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
The compiler cannot find a member with the specified name on the given type.


This error is emitted when a `case class` is defined with the `implicit` modifier. Case classes cannot be implicit in Scala.

Implicit classes may not be case classes. Case classes automatically generate companion
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Implicit classes may not be case classes. Case classes automatically generate companion
Case classes automatically generate companion


This error is emitted when an implicit class has more than one non-implicit parameter in its primary constructor. Implicit classes must accept exactly one primary constructor parameter.

Implicit classes may only take one non-implicit argument in their constructor.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Implicit classes may only take one non-implicit argument in their constructor.

Comment on lines +7 to +10
This error is emitted when the same modifier is specified more than once on a definition.

This happens when you accidentally specify the same modifier twice on a definition.
Each modifier should only appear once.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
This error is emitted when the same modifier is specified more than once on a definition.
This happens when you accidentally specify the same modifier twice on a definition.
Each modifier should only appear once.
This error is emitted when the same modifier is specified more than once on a definition.
Each modifier should only appear once.

Comment on lines +7 to +10
This error is emitted when the underscore (`_`) placeholder syntax is used in a context where it cannot be bound to a parameter.

The `_` placeholder syntax was used where it could not be bound.
Consider explicitly writing the variable binding.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
This error is emitted when the underscore (`_`) placeholder syntax is used in a context where it cannot be bound to a parameter.
The `_` placeholder syntax was used where it could not be bound.
Consider explicitly writing the variable binding.
This error is emitted when the underscore (`_`) placeholder syntax is used in a context where it cannot be bound to a parameter.
Consider explicitly writing the variable binding.

Comment on lines +7 to +10
This error is emitted when an abstract method declaration is missing its return type. Abstract declarations must have explicit return types.

An abstract declaration must have a return type. Without a body, the compiler
cannot infer the type of the method, so it must be explicitly specified.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
This error is emitted when an abstract method declaration is missing its return type. Abstract declarations must have explicit return types.
An abstract declaration must have a return type. Without a body, the compiler
cannot infer the type of the method, so it must be explicitly specified.
This error is emitted when an abstract method declaration is missing its return type. Abstract declarations must have explicit return types. Without a body, the compiler
cannot infer the type of the method, so it must be explicitly specified.


This error is emitted when a variable binding is used in a pattern alternative (`|`). Variables are not allowed in alternative patterns.

Variables are not allowed within alternate pattern matches. When you use the `|`
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Variables are not allowed within alternate pattern matches. When you use the `|`
When you use the `|`

@@ -0,0 +1,17 @@
---
title: E025: Identifier Expected
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shows up in

object obj2:
  val a: this = ???

Copy link
Contributor

@tgodzik tgodzik left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Took a look to the errors up to 50

Comment on lines +7 to +13
This error is emitted when the parser expects an identifier but finds something else, typically when an invalid token is used where a name is required.

The compiler message states: **"identifier expected"**

This can occur when:
- An invalid token is used where an identifier is expected
- A type annotation uses something that is not a valid identifier
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
This error is emitted when the parser expects an identifier but finds something else, typically when an invalid token is used where a name is required.
The compiler message states: **"identifier expected"**
This can occur when:
- An invalid token is used where an identifier is expected
- A type annotation uses something that is not a valid identifier
This error is emitted when the parser expects an identifier but finds something else, typically when an invalid token is used where a name is required.
The compiler message states: **"identifier expected"**
This can occur when for example when a type annotation uses something that is not a valid identifier

otherwise we repeat the above


This restriction exists because varargs can accept zero or more arguments at runtime, so having additional parameters after it would make the call syntax ambiguous.

**Note:** This error code is active in the compiler and is triggered during parsing when validating parameter lists. The exact syntax to reproduce this error in modern Scala 3 requires further investigation, as the parser may produce different errors for malformed parameter lists.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like we should connect this code to

syntaxError(em"spread operator `*` not allowed here; must come last in a parameter list")

@@ -0,0 +1,21 @@
---
title: E028: Illegal Literal
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This one looks dead, I think it's mostly just in case.


This error is emitted when the wildcard type syntax (`_` or `?`) is used in a position where it cannot be bound to a concrete type.

The wildcard type syntax was used where it could not be bound. Replace the wildcard with a non-wildcard type. If the type doesn't matter, try replacing the wildcard with `Any`.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
The wildcard type syntax was used where it could not be bound. Replace the wildcard with a non-wildcard type. If the type doesn't matter, try replacing the wildcard with `Any`.
Replace the wildcard with a non-wildcard type. If the type doesn't matter, try replacing the wildcard with `Any`.

title: E047: Cyclic Reference Involving Implicit
kind: Error
---
# E047: Cyclic Reference Involving Implicit
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this might be another hail mary error -> it might happen, but in a last ditch scenario

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Create a documentation of compiler error codes

3 participants