essenceDocumentation
essenceDocs
on this pageIf you typed JavaScript
Coming from JavaScript?

Diagnostics

Every code the compiler reports, what it means, how to fix it, and which page teaches the construct behind it.

Every error and warning the Essence compiler reports starts with a code in square brackets, such as [missing-return]. This page has one entry per code. Each entry gives the severity, a report the compiler printed, and the fix. Where a page teaches the code, the entry links that section. An entry’s address is its code: /docs/reference/diagnostics#missing-return.

implementation {
	Terminal.print([3, 1, 2]::firstItem(defaultingTo 0)) § 3
}

This program runs and prints 3. essence check still reports a warning about it:

[fallback-never-used]
Warning: This 'defaultingTo' Argument can never be read
   ╭─┤ First.es:2:38 │
   │
 2 │     Terminal.print([3, 1, 2]::firstItem(defaultingTo 0)) § 3
   │                                         ───────┬──────  
   │                                                ╰──────── this fallback can never be read
   │ 
   │ Help: Drop the 'defaultingTo' Argument; the call already answers an Integer.
   │ 
   │ Note: Without it the call answers an Integer, which is never empty.
───╯

A report has four parts:

  • [fallback-never-used] is the code. This page is keyed by it, and so are your editor’s Quick Fixes. A Quick Fix is an edit your editor offers on the underlined span.
  • Warning is the severity. The text after it is the message.
  • The box quotes the source. Each label under a line says what the compiler found at that span.
  • A Help line suggests a fix. A Note line states the rule behind the report.

The severity says what happens next:

  • Error: the program is refused. essence check exits with status 1, essence run runs nothing, and essence build writes nothing. Unlike tsc, the compiler never emits JavaScript for a program with an Error.
  • Warning: the program is valid and runs. essence check exits with status 0.
  • Information: advice that never fails anything. lonely-tag is one.

You cannot silence a code or change its severity. There is no comment like // @ts-expect-error or // eslint-disable-next-line, and no essence.json setting for it.

Where a code has a Quick Fix, its entry gives the title your editor shows. Two entries name a Refactor or a Source Action: the same kind of edit, listed in your editor’s Refactor or Source Action menu rather than on the error. The reports below were printed by essence check, or by essence test for the codes essence check does not report. Nine codes have no printed report. The editor alone reports three of them, three come from the bundler or a failure inside the compiler, and ordinary programs do not reach the other three.

If you typed JavaScript

These twenty-two JavaScript habits cause most first-hour reports, and they are not the whole of what the compiler answers: the foreign-syntax entry below lists the fifty words it knows by name. Nearly all of them report one of three codes — foreign-syntax for a habit written as words or punctuation, operator-not-supported for an operator, and method-called-with-dot for a method reached with a .. Each habit links its row on Coming from JavaScript, which quotes the message and gives the Essence spelling.

Syntax

The parser reports these. A syntax error does not hide the rest of the file: the parser drops the statement it could not read and carries on, and the stages after it check what is left. What a dropped statement declared is not reported as undeclared, and a construct it was written inside is not judged for what is missing from it — one mistake gets one report.

Where that silence applies is where the dropped declaration would have been readable: the block it was written in, from its own line down. A name dropped inside one function’s body is not in scope in the next function along, so a read of it there is reported like any other name nothing declares. A top-level function, type, choice, namespace or protocol is in scope across the whole file wherever it stands, so dropping one of those is silent file-wide. Methods and static properties are the one thing that is never scoped this way: a method dropped out of a namespace body is called from outside that body, so every call of it by that name stays silent.

syntax-error

Error. The parser expected one thing and found another. The message names both.

[syntax-error]
Error: Expected '=' but found '42'.
   ╭─┤ Answer.es:2:18 │
   │
 2 │     constant answer 42
   │                     ─┐  
   │                      ╰── expected '='
───╯

A JavaScript habit the parser recognises is answered by foreign-syntax or operator-not-supported instead, which name the habit. What is left here is the parser’s guess rather than the fix: if (ready) { reports Expected '{' but found '}'. Look the line up in the list above. Otherwise, write what the message says was expected.

Taught on: Programs and values › The shape of a file

unexpected-token

Error. Something follows the end of the program. A stray } is the usual cause.

[unexpected-token]
Error: Unexpected '}' after the end of the Program
   ╭─┤ Answer.es:4:1 │
   │
 3 │ }
   │ ▲  
   │ ╰── the implementation block ends here
 4 │ }
   │ ▲  
   │ ╰── nothing may follow here
   │ 
   │ Help: Remove the '}'.
   │ 
   │ Note: A Program is one 'implementation { … }' block, framed by an optional 'import { … }' block above it and an optional 'tests { … }' and 'export { … }' block below it.
───╯

Delete it. A file holds one implementation { … } block, with an optional import { … } block above it, and optional export { … } and tests { … } blocks below it, in that order.

Where what follows ends in the } written for the implementation block, a } too many above it ended the block early. The report then stands on that brace, and its help removes it:

[unexpected-token]
Error: This '}' ends the implementation block early
   ╭─┤ Answer.es:4:3 │
   │
 4 │     }}
   │      ▲  
   │      ╰── the implementation block ends here
   │ 
 6 │     Terminal.print(answer())
   │     ────┬───  
   │         ╰───── so this stands after the end of the Program
 7 │ }
   │ ▲  
   │ ╰── and this '}' was written to close the block
   │ 
   │ Help: Remove the '}'.
   │ 
   │ Note: What follows the block closes one more '}' than it opens, so it was written inside the block.
───╯

A tests block closed early is answered the same way. Other code written after the program, such as constant other = 1 below the block, is answered “Move what follows into the ‘implementation { … }’ block, or remove it.” A file of tests alone has no implementation block, and its tests block may hold statements, so it is told to move the code there instead. Removing the first word alone would only leave the next one to report.

Quick Fix: Remove the ‘}’ — the span the report stands on is what goes. Code written after the program gets none, since moving it in is your edit.

Taught on: Programs and values › The shape of a file

unclosed-string

Error. A string literal runs to the end of the file without its closing ". The report points at the opening quote and at the end of the input. Every string can hold a hole, { … }, with an expression in it, so a { in a string opens one. A " inside the hole does not close the string: JSON written as "{\"a\": 1}" reports this code.

[unclosed-string]
Error: This String Literal is never closed
   ╭─┤ Greeting.es:3:2 │
   │
 2 │     constant greeting = "Hello
   │                         ▲  
   │                         ╰── opened here
 3 │ }
   │  │ 
   │  ╰─ the input ends here
   │ 
   │ Help: Add the missing '"' at the end of line 2.
───╯

A literal may span lines, so a missing " has two readings: the string ran on, or the quote that appeared to close it was written to open the next one. Where a string that spans lines closes on the very line the unclosed one opens on, the report names the spanning string instead — the quote missing from the end of its first line is the one mistake that explains the file — and points at the quote that closed it and at the end of the input beside it.

[unclosed-string]
Error: This String Literal is never closed
   ╭─┤ Greeting.es:2:22 │
   │
 2 │     constant greeting = "Hello
   │                         ▲  
   │                         ╰── opened here
 3 │     constant name = "Ada"
   │                     ▲  
   │                     ╰── closed by this quote, which reads as the start of another String
   │ 
 6 │ }
   │  │ 
   │  ╰─ and the input ends inside that one
   │ 
   │ Help: Add the missing '"' at the end of line 2.
   │ 
   │ Note 1: A String Literal may span lines, and the line breaks are part of it — so the quote on line 3 closed the one opened on line 2, and the String that quote was written to open is the one that ran to the end of the input.
   │ Note 2: One '"' is missing either way, and where it goes decides which String is which: at the end of line 2 the lines below are Statements, and at the end of the input they are text. It is reported against the String that spans lines, because a String written to span them is not usually followed, on the line it closes, by a second one that never closes at all.
───╯

Add the closing ". Only the one reading is offered as an edit: writing the quote at the end of the input instead closes a string holding every line below it, and the quotes standing in those lines close it early all over again, so it reaches no program. The other reading is the second note.

A string whose { opened a hole is a different mistake, and is answered as one — the quote is not what is missing there, and writing one leaves the same report standing:

[unclosed-string]
Error: This String Literal is never closed
   ╭─┤ Body.es:4:2 │
   │
 2 │     constant body = "{\"a\": 1}"
   │                     ▲  
   │                     ╰── opened here, and a '{' inside it opens a hole
   │ 
 4 │ }
   │  │ 
   │  ╰─ the input ends here
   │ 
   │ Help: Write '\{' and '\}' for the braces that stand for themselves.
   │ 
   │ Note: A '{' inside a String opens a hole, which holds an Expression — so the text between the braces is read as one, and a quote written inside it opens a String of its own.
───╯

For a literal brace, write \{ and \}: "\{\"a\": 1\}" prints {"a": 1}.

A quote written inside a hole opens a string of its own, and a quote added after it only opens another. "a } b { c" is answered with the hole’s { and the first quote inside the hole:

[unclosed-string]
Error: This String Literal is never closed
   ╭─┤ Label.es:4:2 │
   │
 2 │     constant label = "a } b { c"
   │                             ▲  ▲  
   │                             ╰──│── this '{' opens a hole
   │                                │  
   │                                ╰── and this quote opens a String inside it
   │ 
 4 │ }
   │  │ 
   │  ╰─ the input ends here
   │ 
   │ Help 1: Write '\{' for a brace that stands for itself.
   │ Help 2: Or end the hole with a '}' in front of that quote, where it holds an Expression.
   │ 
   │ Note: A '{' inside a String opens a hole, which holds an Expression — so a quote written inside it opens a String of its own.
───╯

Which edit is right depends on what was meant. "a } b \{ c" prints a } b { c. "Hello, {name" lost the } of a hole that holds an expression, and "Hello, {name}" reads name.

Quick Fix: Add the missing ‘“’ — withheld for both holes, where it would produce a file carrying the very report it answers. For a quote inside a hole, Write ‘{’ for the brace and End the hole in front of the quote make the two edits, neither preferred.

Taught on: Programs and values › Strings

unclosed-block

Error. A { is never closed. Where a } below the mistake is written further out than the brace it was meant for, the report is about the block that lost its brace: it points at that block’s {, and at the } that closed it instead.

[unclosed-block]
Error: This block is never closed
   ╭─┤ Greeting.es:2:43 │
   │
 2 │     function greet(_ name: String) -> String {
   │                                              ▲  
   │                                              ╰── this block is never closed
   │ 
 4 │ }
   │ ▲  
   │ ╰── this '}' is written further out, so it closes the block around it
   │ 
   │ Help: Write the '}' where this block's Statements end.
   │ 
   │ Note: Which block a '}' closes is counted rather than read off the indentation, so a file one brace short hands every '}' below the mistake to the block above the one it was written for — and the end of the input is where that is noticed.
───╯

Here the function has no } of its own, so the file’s last } closes the function, and implementation is the block left open. Write a } after <- name.

Where no } stands further out than its opener — a file that simply ends short of its braces — there is no second brace to point at, so the report names the innermost open block and the end of the input:

[unclosed-block]
Error: This block is never closed
   ╭─┤ Greeting.es:2:29 │
   │
 1 │ implementation {
   │                ▲  
   │                ╰── opened here
 2 │     constant greeting = "Hello"
   │                                │ 
   │                                ╰─ the input ends here
   │ 
   │ Help: Add the missing '}'.
───╯

Close every open block. Where more than one is open, the help counts them: Add a '}' for each of the 2 blocks still open.

invalid-number

Error. A number literal holds something other than digits. Essence has no hexadecimal, binary or exponent form. A trailing ; is answered by foreign-syntax instead.

[invalid-number]
Error: '0xFF' is not a valid Number
   ╭─┤ Mask.es:2:18 │
   │
 2 │     constant mask = 0xFF
   │                     ──┬─  
   │                       ╰─── this is not a Number
   │ 
   │ Help: Essence has no hexadecimal, binary or exponent form; write the value in digits.
   │ 
   │ Note: A Number is written in the digits '0' through '9', grouped with '_' where that helps, with a fractional part written behind a '.' — 1_000_000, 19.99.
───╯

Write the value in the digits 0 to 9, such as 255 for 0xFF. Group digits with _ and write a fraction part after a .. Delete a trailing ;.

Taught on: Programs and values › Integers

mixed-rational-literal

Error. A rational literal is written as a fraction and a decimal at once, such as 1.5/2.

[mixed-rational-literal]
Error: A Rational Literal is a fraction or a decimal, not both
   ╭─┤ Half.es:2:19 │
   │
 2 │     constant ratio = 1.5/2
   │                      ──┬──  
   │                        ╰──── '/' can not follow a decimal
   │ 
   │ Help: Write it as '3/4' — or as '0.75', which is the same value written the other way.
   │ 
   │ Note: A fraction and a decimal are two spellings of one Rational — '3/4' and '0.75' are the same value — so a Literal written both ways says the same thing twice, and leaves it to the reader which parts belong to which.
───╯

Write one spelling: 3/4 or 0.75. Both are the same exact Rational, and both print as 3/4. The help spells the value the two spellings say between them, out of the same arithmetic the quick fix uses — 2.5/3 is five sixths, so it is answered Write it as '5/6' and offers no decimal, there being none that says it.

Quick Fix: Write it as ‘3/4’ or Write it as ‘0.75’, each writing the value in one spelling.

Taught on: Programs and values › Rationals

partial-decimal-literal

Error. A decimal literal has nothing on one side of its point, such as .5 or 1..

[partial-decimal-literal]
Error: A decimal Literal has digits on both sides of the dot
   ╭─┤ Half.es:2:18 │
   │
 2 │     constant half = .5
   │                     ─┐  
   │                      ╰── nothing stands before the point
   │ 
   │ Help: Write the digits before the point: '0.5'.
   │ 
   │ Note: A '.' that opens an Expression is a member path — '.price' reads a member off the value it is handed — and digits can not name a member, so this is a decimal missing its whole part rather than a path.
───╯

Write digits on both sides: 0.5, 1.0. Drop the point instead when you meant a whole number: 1.

Quick Fix: Write it as ‘0.5’. A trailing point is offered both 1.0 and 1.

Taught on: Programs and values › Rationals

invalid-escape

Error. A backslash in a string is followed by a character that is not an escape. The escapes are \", \\, \n, \r, \t, \{, \} and \u{…}. \{ and \} write a brace, because every string can hold { … } holes, not only a template literal.

[invalid-escape]
Error: '\d' is not a valid escape
   ╭─┤ Path.es:2:23 │
   │
 2 │     constant folder = "C:\data"
   │                          ─┐  
   │                           ╰── this escape is not known
   │ 
   │ Help: Write '\\' for a literal backslash, or drop the backslash to keep the character as itself.
   │ 
   │ Note: A String understands '\"', '\\', '\n', '\r', '\t', '\{', '\}' and '\u{…}'; every other backslash is an error.
───╯

Write \\ for a backslash: "C:\\data" prints C:\data. Drop the backslash if it was a typo.

Quick Fix: Write ‘\\’ for a literal backslash or Drop the backslash.

Taught on: Programs and values › Strings

unbraced-unicode-escape

Error. A \u is written without the braces around its code point. JavaScript and JSON spell a character that way — \u00e9, four digits and no braces — and Essence spells it \u{e9}, one to six digits in braces.

[unbraced-unicode-escape]
Error: '\u00e9' is missing the braces around its code point
   ╭─┤ cafe.es:2:21 │
   │
 2 │     Terminal.print("caf\u00e9")
   │                        ───┬──  
   │                           ╰──── a code point is written in braces
   │ 
   │ Help: Write it in braces: '\u{e9}'.
   │ 
   │ Note: A Unicode escape is written '\u{…}' — one to six hexadecimal digits in braces, naming one character.
───╯

The Help rebrackets exactly the digits JavaScript would have read, which is four of them where four are written: "\u0041BC" is A followed by BC there, so the Help offers \u{41} and leaves BC alone. A surrogate pair — "\uD83D\uDE00", how a language with no astral escape writes one character — is answered with the single escape both halves stood for, \u{1F600}.

Quick Fix: Write it as ‘\u{e9}’ — the spelling the report named, whichever it named.

Taught on: Programs and values › Strings

malformed-unicode-escape

Error. A \u{…} is not written as one to six hexadecimal digits in braces. The braces may hold nothing ("\u{}"), hold a character that is not a hexadecimal digit ("\u{1G}"), hold more than six digits ("\u{0000041}"), or never close ("\u{1B").

[malformed-unicode-escape]
Error: 'G' is not a hexadecimal digit
   ╭─┤ Digits.es:2:18 │
   │
 2 │     Terminal.print("\u{1G}")
   │                     ───┬──  
   │                        ╰──── a code point is written in hexadecimal
   │ 
   │ Help: Write the code point in hexadecimal: '\u{1B}' is the escape character, '\u{1F600}' a grinning face.
   │ 
   │ Note: A Unicode escape is written '\u{…}' — one to six hexadecimal digits in braces, naming one character.
───╯

An escape that never closes stops at the closing quote without consuming it, so the string ends where it was written and every statement below it is still read. Leading zeros are the usual cause of a seventh digit, and the Help takes them off. U+1B written between the braces is answered by taking the U+ off: that is how a code point is named, not how it is spelled.

Quick Fix: Write it as ‘\u{41}’ — offered wherever the report spells a rewrite, which is the seventh digit, the escape that never closed, and the U+ written between the braces. Braces holding nothing or holding a character that is not a digit are offered none: what was meant there is not something the source says.

Taught on: Programs and values › Strings

unicode-escape-out-of-range

Error. A \u{…} names a number above U+10FFFF, which is the highest Unicode code point there is.

[unicode-escape-out-of-range]
Error: U+128512 is above the highest character
   ╭─┤ Chart.es:2:18 │
   │
 2 │     Terminal.print("\u{128512}")
   │                     ─────┬────  
   │                          ╰────── no character has this code point
   │ 
   │ Help: The digits are read as hexadecimal — write '\u{1F600}' where the character numbered 128512 was meant.
   │ 
   │ Note: The highest Unicode code point is U+10FFFF, so '\u{10FFFF}' is the largest escape there is.
───╯

Every decimal digit is a hexadecimal digit too, so a code point copied off a chart in decimal looks exactly like a well-written escape and simply names a number that is too large. The Help offers the hexadecimal spelling on that condition rather than assuming it — where the character numbered 128512 was meant is the condition, and which base was meant is the one thing the source does not record. It is the one Help among the escapes with no Quick Fix behind it: applying it would decide for the reader which base they had in mind.

It is withheld just above the top. "\u{110000}" is U+10FFFF missed by one in hexadecimal, written by somebody who knows exactly where the top is, and so is the whole of the first plane above the last real one: asking them whether they meant the decimal 110,000 answers a question nobody asked. The refusal itself is the whole of what those need.

Taught on: Programs and values › Strings

surrogate-unicode-escape

Error. A \u{…} names a code point between U+D800 and U+DFFF. Those are the two halves UTF-16 writes a character above U+FFFF in, and neither of them names a character on its own.

[surrogate-unicode-escape]
Error: U+D83D is a surrogate, which names no character
   ╭─┤ Half.es:2:18 │
   │
 2 │     Terminal.print("\u{D83D}")
   │                     ────┬───  
   │                         ╰───── this is half of a character, not one
   │ 
   │ Note: U+D800 through U+DFFF are the halves UTF-16 writes a character above U+FFFF in; a String holds characters, so an escape names one of those directly.
───╯

No Help is offered for a lone surrogate, and so no Quick Fix either, because there is no character it stands for. A string holds characters rather than the units they are stored in, so an astral character is always written as a single escape.

Where the other half stands directly behind it, the two are one mistake and are reported as one — over both escapes, whichever way each half is spelled (\uD83D\uDE00, \u{D83D}\u{DE00} and the two mixtures of them all read alike):

[surrogate-unicode-escape]
Error: U+D83D and U+DE00 are the two halves of one character
   ╭─┤ Halves.es:2:18 │
   │
 2 │     Terminal.print("\u{D83D}\u{DE00}")
   │                     ────────┬───────  
   │                             ╰───────── one character, written as the units it is stored in
   │ 
   │ Help: Write the character as one escape: '\u{1F600}'.
   │ 
   │ Note: U+D800 through U+DFFF are the halves UTF-16 writes a character above U+FFFF in; a String holds characters, so an escape names one of those directly.
───╯

Quick Fix: Write it as ‘\u{1F600}’, where a pair was written — it replaces both escapes, so following it leaves nothing behind.

Taught on: Programs and values › Strings

comment-in-hole

Error. A § comment is written inside a string’s { … } hole. A comment runs to the end of its line, so it would swallow the hole’s } and the closing ".

[comment-in-hole]
Error: A Comment can not be written inside an interpolation hole
   ╭─┤ Label.es:2:33 │
   │
 2 │     constant label = "answer: { 42 § the answer }"
   │                                    ──────┬──────  
   │                                          ╰──────── this Comment would swallow the rest of the String
   │ 
   │ Help: Move the Comment out of the String — behind the closing '"' works.
   │ 
   │ Note: A Comment runs to the end of its line — inside a hole it would take the hole's '}' and the String's closing '"' with it.
───╯

Move the comment out of the string, for example behind the closing quote: constant label = "answer: { 42 }" § the answer.

Taught on: Programs and values › Comments

nesting-too-deep

Error. Code nests 1,024 levels deep at one point, for example 1,024 lists inside each other. The parser stops at that depth with this error.

Name the inner values as constants, or the inner types as type aliases, so that no single expression nests that deep.

redundant-parameter-label

Error. A parameter of a function literal has two names and no type, such as (each number). A parameter without a type takes its label from the function type it is passed to.

[redundant-parameter-label]
Error: A Parameter without a Type can not carry a label
   ╭─┤ Double.es:2:37 │
   │
 2 │     constant doubled = [1, 2, 3]::map((each number) { <- number::multiply(with 2) })
   │                                        ─────┬─────  
   │                                             ╰─────── two names, no Type
   │ 
   │ Help: Write only 'number'.
   │ 
   │ Note: Such a Parameter takes its label from the expected Function Type.
───╯

Write only the name: [1, 2, 3]::map((number) { <- number::multiply(with 2) }).

Quick Fix: Remove the label.

Taught on: Functions as values › Writing some of a literal’s types

reserved-parameter-label

Error. A parameter’s label is spelled start or complete. Both words open an expression where a label would stand, so compute(start 1) is a start of 1 and never an argument labelled start — a parameter asking for that label could not be written at a call at all.

[reserved-parameter-label]
Error: A Parameter's label can not be spelled 'start'
   ╭─┤ Compute.es:2:19 │
   │
 2 │     function compute(start value: Integer) -> Integer {
   │                      ──┬──  
   │                        ╰──── this word opens an Expression
   │ 
   │ Help 1: Name the label another word.
   │ Help 2: Or write '_' in its place, so the Parameter takes no label at all.
   │ 
   │ Note: An Argument written 'start value' reads as a 'start' of the value, so no call could pass this Parameter by name.
───╯

Name the label another word, or write _ in its place so the parameter takes none: function compute(_ value: Integer).

Taught on: Asynchrony › Two words that are also names

shorthand-in-combination

Error. An update’s key list holds a bare name, as in { base with port, host }. The shorthand { port } belongs to a record literal. JavaScript’s { ...base, port } sets port from a variable of that name, but after with a bare name is a whole record to merge in.

[shorthand-in-combination]
Error: A bare member name is not a key in an update
   ╭─┤ Server.es:5:32 │
   │
 5 │     constant server = { base with port, host }
   │                                   ──┬─  
   │                                     ╰─── this names no value to set
   │ 
   │ Help 1: Write 'port = port'.
   │ Help 2: Or merge a whole Record: '{ base with { port, host } }'.
   │ 
   │ Note: An update's key list always spells its values, because a bare name after 'with' is already the value being merged in.
───╯

Write each value, { base with port = port, host = host }, or merge a record literal that uses the shorthand: { base with { port, host } }. One report stands per bare name, and each of them offers the same record — holding every key, a written one as name = … to take the value you wrote, so that following one does not drop the others in silence. A name with no binding in scope is answered Write the value it sets in place of '…': 'host = …'. instead. The record is offered only where every name is bound and no path key is written, since a path key reaches into nothing in a record literal. The unbound name is not reported again as unknown-name.

Quick Fix: Write ‘port = port’, where port is in scope.

Taught on: Records › When the compiler refuses a record

dictionary-entry-syntax

Error. A dictionary entry uses a separator other than =, such as ["kim": 7].

[dictionary-entry-syntax]
Error: A Dictionary entry is written with '='
   ╭─┤ Ages.es:2:24 │
   │
 2 │     constant ages = ["kim": 7]
   │                           ▲  
   │                           ╰── expected '=' and found ':'
   │ 
   │ Help: Write '=' in place of ':'.
   │ 
   │ Note: An entry is 'key = value', and a Dictionary is a bracket list of them: '["a" = 1, "b" = 2]'.
───╯

Write each entry as key = value: ["kim" = 7]. Ruby’s hash rocket reports this code too: ["kim" => 7] is answered expected '=' and found '=>'. A => behind a NAME is left to foreign-syntax and its function literal — x => x is a function in one language and a key in another, and no language writes a parameter list as a string or a number.

Taught on: Dictionaries › Writing a dictionary

shorthand-on-path-key

Error. A dotted key in an update’s key list has no value, as in { config with server.port, name = "cache" }. A path is not a name in scope, so it cannot stand for its own value.

[shorthand-on-path-key]
Error: A path key names no binding
   ╭─┤ Config.es:4:33 │
   │
 4 │     constant moved = { config with server.port, name = "cache" }
   │                                    ─────┬─────  
   │                                         ╰─────── this reaches into a value to set
   │ 
   │ Help: Write 'server.port = port'.
   │ 
   │ Note: A bare name is a member and its own value; a path is neither, because the value it would set is not the name it reaches through.
───╯

Write the value: { config with server.port = port, name = "cache" }. The help writes port only where a port is in scope. Where none is, it asks for the value instead, Write the value it sets in place of '…': 'server.port = …'., and the report is the only one: the name is not reported again as unknown-name.

Quick Fix: Write ‘server.port = port’, where port is in scope.

empty-path-group

Error. The braces after a path key are empty, as in { config with server.{ } }.

[empty-path-group]
Error: This descend updates nothing
   ╭─┤ Config.es:3:32 │
   │
 3 │     constant same = { config with server.{ } }
   │                                   ─────┬────  
   │                                        ╰────── no member is written here
   │ 
   │ Help 1: Write the members to update inside it.
   │ Help 2: Or drop the key — and where it is the only one, drop the update with it and write 'config' on its own.
   │ 
   │ Note: An update writes the members it names, so a descend with none in it says to leave 'server' exactly as it is.
───╯

Write the members to change inside the braces, { config with server.{ port = 8080 } }, or remove the key. Dropping the only key leaves { config with }, which is a syntax error — so the second help names the value the update was written on, which is what an update setting nothing was going to answer anyway.

Taught on: Records › When the compiler refuses a record

path-is-members-only

Error. A member path such as .price is followed by :: or (. A path reads members and cannot carry a call.

[path-is-members-only]
Error: A member path reads members and nothing else
   ╭─┤ Prices.es:2:47 │
   │
 2 │     constant labels = [{ price = 3 }]::map(.price::toString())
   │                                                  ▲  
   │                                                  ╰── '::' can not follow a path
   │ 
   │ Help: Write the Function literal instead: '(_ item) { <- item.price::toString() }'.
   │ 
   │ Note: A path is the Function that reads those members off its Argument, so there is nothing here for a call to be made on.
───╯

Write a function literal instead: [{ price = 3 }]::map((item) { <- item.price::toString() }). The help spells the path and the call that were written, and leaves the offered parameter unannotated: a literal handed to a method reads its parameter’s type off the argument it is passed.

Taught on: Functions as values › Member paths

default-on-function-literal

Error. A parameter of a function literal has a default value. A literal is called through its function type, which fixes how many arguments every call passes, so the default could never apply.

[default-on-function-literal]
Error: A Function literal can not carry a default
   ╭─┤ Double.es:2:41 │
   │
 2 │     constant double = (_ number: Integer = 1) -> Integer { <- number::multiply(with 2) }
   │                                            ▲  
   │                                            ╰── this default
   │ 
   │ Help: Remove the default.
   │ 
   │ Note 1: A Function literal is called through the Function Type it was written for, which fixes how many Arguments every call passes, so a default here could never be reached.
   │ Note 2: A default belongs to a named Function or Method, whose Parameter list is part of the Declaration a call is resolved against.
───╯

Remove the default. Where one is wanted, declare a named function or method — a literal is often passed to nothing at all, or to a method of the standard library, so there is no other declaration to write it on.

Quick Fix: Remove the default.

Taught on: Functions › Default values

case-default-without-payload

Error. A case without a payload is given a default, as in Up = { degrees = 0 }. A default fills in payload members, and this case has none.

[case-default-without-payload]
Error: Case '#Up' carries no payload to default
   ╭─┤ Direction.es:3:8 │
   │
 3 │        Up = { degrees = 0 },
   │             ───────┬───────  
   │                    ╰───────── this default
   │ 
   │ Help: Give '#Up' a payload shape, or write it on its own.
   │ 
   │ Note: A default fills members in for a construction that left them out, and a Case with no payload shape has none.
───╯

Give the case a payload shape, Up { degrees: Integer } = { degrees = 0 }, or remove the default.

Quick Fix: Remove the default.

Taught on: Choices and match › Defaults for a payload

case-payload-is-one-value

Error. A case’s payload ends on a comma. The parentheses of a case hold the single value it carries, not a list, so a separator there has nothing to separate.

[case-payload-is-one-value]
Error: A Case carries one value
   ╭─┤ Answer.es:3:5 │
   │
 3 │        42,
   │          ▲  
   │          ╰── nothing follows this ','
   │ 
   │ Help: Drop the ','.
   │ 
   │ Note: The parentheses of a Case hold the single value it carries, not a list.
───╯

Drop the comma. A comma with a SECOND value behind it is a different report from the same code — dropping it there would leave two values written flush against each other, so the help offers the record instead, named for the case that was written: #Rect(2, 3) is answered Carry the values as one Record: '#Rect({ … })', with a member for each of them.

Taught on: Choices and match › Building a case

case-application-across-lines

Error. A case applied to type arguments has its # on a line of its own. A construction is written on one line: the bare form Box#Full reads as one only where the # sits flush against the name, and writing the type arguments in between is not a way around that.

[case-application-across-lines]
Error: A Case is applied on the line its Type Arguments close on
   ╭─┤ Applied.es:3:3 │
   │
 3 │        #Value(42)
   │        ▲  
   │        ╰── this '#' is on a line of its own
   │ 
   │ Help: Write the '#' and its Case on the line the '>' closes on.
   │ 
   │ Note: The bare form is held to the same rule: 'Box#Full' is one construction only where the '#' sits against the name.
───╯

Write the # and its case on the line the > closes on.

Taught on: Choices and match › Building a case

declarations-outside-stdlib

Error. A file opens with declarations { … }. That form belongs to the standard library’s own sources.

[declarations-outside-stdlib]
Error: Only the standard library may open a 'declarations' block
   ╭─┤ Answer.es:1:1 │
   │
 1 │ declarations {
   │ ──────┬─────  
   │       ╰─────── 'declarations' is not allowed here
   │ 
   │ Help: Open the Program with 'implementation { … }' instead.
───╯

Open the file with implementation { … }.

Quick Fix: Open the Program with ‘implementation’.

Taught on: Modules › The Prelude

overload-function-outside-stdlib

Error. A program writes an overload function block. A free function in a program has one signature. Only the standard library declares a free function with overloads, such as loop.

[overload-function-outside-stdlib]
Error: Only the standard library may write an 'overload function' block
   ╭─┤ Combine.es:2:2 │
   │
 2 │     overload function combine {
   │     ────┬───  
   │         ╰───── 'overload function' is not allowed here
   │ 
   │ Help: Write the Overloads as an 'overload' Method block inside a Namespace instead.
   │ 
   │ Note: Free-Function Overloads are a 'declarations { … }' form — a free Function in a Program carries one signature.
───╯

With one signature, write a plain function: function combine(first value: Integer) -> Integer { <- value }. For several, write an overload combine { … } block inside a namespace.

Taught on: Namespaces and methods › Overloads

misplaced-module-section

Error. A module block is out of order. A file reads import { … }, then implementation { … }, then export { … }.

[misplaced-module-section]
Error: The 'export { … }' block belongs below the implementation
   ╭─┤ Answer.es:1:1 │
   │
 1 │     export { answer }
   │     ───┬──  
   │        ╰──── this block is written above the implementation
   │ 
 3 │ ╭─▶ implementation {
 4 │ │       constant answer = 42
 5 │ ├─▶ }
   │ │       
   │ ╰─────── the implementation block is here
   │ 
   │ Help: Move the 'export { … }' block below 'implementation { … }'.
   │ 
   │ Note: A Program reads top to bottom: what it imports, what it does, what it exports.
───╯

Move the block to its place. Where a block of its kind already stands there, move its entries into that one instead, since a file holds one of each.

Quick Fix: Move the ‘export { … }’ block below the implementation, or Move the ‘import { … }’ block above the implementation. Where a block of its kind already stands there: Move the entries into the ‘import { … }’ block above the implementation, or the same for export.

Taught on: Modules › The four blocks of a file

foreign-syntax

Error. The line is written in another language. The message names the habit and the note names the Essence spelling. Every row of Coming from JavaScript that reports this one gives the rewritten line.

[foreign-syntax]
Error: 'const' is not how Essence declares a binding
   ╭─┤ Total.es:2:2 │
   │
 2 │     const total = 1
   │     ──┬──  
   │       ╰──── Essence writes 'constant' here
   │ 
   │ Help: Write 'constant' in place of 'const'.
   │ 
   │ Note: A binding is declared with 'constant', or with 'variable' where it is reassigned; there is no third form.
───╯

One code covers the family, and the message says which habit was written. It answers fifty words, and fourteen habits written in punctuation, quotes or brackets.

The punctuation: a ; at the end of a statement; { x: 1 } for a record member; point.x = 2; (n) => n; c ? a : b; // a comment and /* a comment */; 'hi' and `hi` for a string; identity<Integer>(1); primes[0] and ages["ada"] for an item read by position or key, and primes[0] = 5 for one written by position; user! and user?.name; and (total), parentheses that group one value.

The words: const, let, var, mut and return; null, undefined, nil, None and Some; this and self; print, println, println!, puts, echo and fmt; len, console, Math, parseInt, parseFloat, NaN and Infinity; new, class, def, fn and func; elif, guard, switch, typeof and instanceof; throw, try and catch; while, break and continue; enum, interface, implements and extends; async and await; and Map, Set and require.

A declaration keyword is reported once and read on: const price = 12 declares price for the rest of the file, so one mistake is one report rather than one per line that reads it. An index recovers the same way, and has to: constant first = primes[0] keeps first declared, bound to an error rather than to the list in front of the brackets, so neither the name nor its type is reported about again. Grouping parentheses are read past to the value inside them: constant total = (1::add(2)) keeps total declared as 1::add(2), so the parentheses are the only report.

An index with an = behind it is a write, and is answered about writing: primes[0] = 5 gets A value is not written into with brackets, the methods that rebuild a list and a dictionary — primes = primes::replace(5, at 0), ages = ages::set("ada", to 37) — and the whole statement, since nothing changes a collection in place. That one is refused rather than read on: what follows the = is the value being stored, and reading on would answer it as a statement of its own.

An index is refused by its spacing. A [ written flush against the value in front of it is an index; one written a space behind a name is the list that name labels, as in append(contentsOf [4]). That is the rule # and . are already read by — see A label sits in front of its value.

Quick Fix: Write ‘constant’ instead of ‘const’, and its equivalent wherever one word replaces one word. Remove the parentheses removes both of a grouping pair. There is none where the fix is a restructuring — a => body, a ternary, a member assignment.

Taught on: Coming from JavaScript

operator-not-supported

Error. An operator stands where a method call belongs. Essence has none: arithmetic, comparison and logic are methods, read left to right.

[operator-not-supported]
Error: Essence has no '+' operator
   ╭─┤ Sum.es:2:21 │
   │
 2 │     constant total = 1 + 2
   │                        ▲  
   │                        ╰── this is not a Method call
   │ 
   │ Help 1: Write 'a::add(b)' for Numbers.
   │ Help 2: Write 'a::append(b)' to join two Strings.
   │ 
   │ Note: Arithmetic, comparison and logic are Method calls in Essence, read left to right — there are no operators, and so no precedence to remember.
───╯

The helps name the method for the operator that was written. The operator table has all of them in one place.

A compound assignment is spelled with the operands that were written: tally += 5 is answered Write 'tally = tally::add(5)', and hits++ with Write 'hits = hits::add(1)'. Where the right operand is an expression of its own rather than one literal or name, the help writes … in its place. &, ^, << and >> carry no help at all — there is no method to write instead, and that is said as a note: Essence has no bitwise operations, and no Method stands in for one.

!ready and a+b report this from the enricher rather than the parser: neither character ends a name, so each is read as one name and is not refused until nothing declares it.

There is no Quick Fix. The rewrite moves the left operand in front of a :: and the right one into an argument list, which is a restructuring rather than a substitution — and the parser refuses at the operator, with only the left operand read.

Taught on: Method calls

Names

A name that is declared twice, never declared, or used where it cannot be.

duplicate-variable

Error. A name is declared twice in the same scope. The message says “Variable” for a constant too.

[duplicate-variable]
Error: Variable 'total' is already declared
   ╭─┤ Total.es:3:11 │
   │
 2 │     constant total = 1
   │              ──┬──  
   │                ╰──── first declared here
 3 │     constant total = 2
   │              ──┬──  
   │                ╰──── declared a second time here
───╯

Rename one of the two. To change a value, declare it once with variable and assign to it.

Taught on: Functions › Scope and hoisting

duplicate-type

Error. A type name is declared twice.

[duplicate-type]
Error: Type 'Point' is already declared
   ╭─┤ Point.es:3:7 │
   │
 3 │     type Point = { x: Integer }
   │          ──┬──  
   │            ╰──── declared a second time here
───╯

Rename one of them. A name from the standard library is taken too, so type Step = … reports this code.

Taught on: Namespaces and methods › Where a namespace can be used

duplicate-protocol

Error. A protocol name is declared twice.

[duplicate-protocol]
Error: Protocol 'Sized' is already declared
   ╭─┤ Sized.es:6:11 │
   │
 6 │     protocol Sized {
   │              ──┬──  
   │                ╰──── declared a second time here
───╯

Rename one of them, or delete the copy.

Taught on: Protocols › Declaring a protocol

duplicate-case

Error. A choice declares the same case twice.

[duplicate-case]
Error: Case '#Red' is declared more than once
   ╭─┤ Colour.es:5:3 │
   │
 5 │        Red,
   │        ─┬─  
   │         ╰─── declared a second time here
   │ 
   │ Help: Remove this 'Red', or give it a name of its own.
───╯

Remove or rename the second one. The choice has the FIRST — the second declaration is skipped — so it is the one the help points at.

Taught on: Choices and match › Building a case

duplicate-method

Error. A namespace defines two methods with the same name.

[duplicate-method]
Error: Method 'shout' is already defined
   ╭─┤ Loud.es:7:3 │
   │
 3 │        shout() -> String {
   │        ──┬──  
   │          ╰──── first defined here
   │ 
 7 │        shout() -> String {
   │        ──┬──  
   │          ╰──── defined a second time here
   │ 
   │ Help: Write both signatures inside one 'overload' block when both are meant to exist.
───╯

Rename one of them. When both are meant to exist, write both signatures in one overload shout { … } block.

duplicate-type-parameter

Error. One <…> list names the same type parameter twice. Only one of the two can take effect — the last one written — so the first is dropped, which is what this refuses to do in silence.

[duplicate-type-parameter]
Error: Type Parameter 'Item' is declared twice
   ╭─┤ Ranked.es:3:32 │
   │
 3 │        describe<Item is Comparable, Item is Printable>() -> String {
   │                 ─────────┬────────  ────────┬────────  
   │                          ╰──────────────────│────────── first declared here
   │                                             │          
   │                                             ╰──────── this bound replaces the one above
   │ 
   │ Help: Keep the one the body needs: write '<Item is Comparable>' or '<Item is Printable>', not both.
   │ 
   │ Note 1: 'Item' is bounded by 'Comparable' already, and a Type Parameter carries ONE bound — a second would replace it rather than stand beside it.
   │ Note 2: A Protocol that extends both — 'protocol Ranked is Comparable, is Printable {}' — is how a Parameter asks for two, and only Types this Program can declare that conformance for can satisfy it.
───╯

The same words cover every <…> in the language — a function’s, a method’s, a choice’s, a namespace’s, a type alias’. The list still parses, so essence format keeps working on the file: this is one line that is wrong, not a file the toolchain stops handling.

Two bounds on one parameter is the case worth spelling out: a type parameter carries ONE bound today, so <Item is Comparable, Item is Printable> is not a parameter bounded by both, it is <Item is Printable> with a line of the reader’s intent thrown away. Write the one the body needs; where the body needs the other as well, unsatisfied-bound names it at the call that wants it.

A protocol that extends both — protocol Ranked is Comparable, is Printable {} — is how a parameter asks for two. It is not offered as a Help because it only works for types this program can declare the conformance for: conforming a standard library type to it makes every other call that used the parent protocols ambiguous.

duplicate-property

Error. A namespace declares the same static property twice.

[duplicate-property]
Error: Property 'retries' is already defined
   ╭─┤ Retries.es:4:10 │
   │
 3 │        static retries = 3
   │               ───┬───  
   │                  ╰───── first defined here
 4 │        static retries = 5
   │               ───┬───  
   │                  ╰───── defined a second time here
   │ 
   │ Help: Remove the second 'retries', or give it a name of its own.
───╯

Rename or remove one of them.

duplicate-member

Error. A record names the same member twice, such as { x = 1, x = 2 }. A record holds one value per name.

[duplicate-member]
Error: Member 'x' is already defined
   ╭─┤ Point.es:2:28 │
   │
 2 │     constant point = { x = 1, x = 2 }
   │                        ▲      ▲  
   │                        ╰──────│── first defined here
   │                               │  
   │                               ╰── defined a second time here
   │ 
   │ Help: Remove the second 'x', or give it a name of its own.
───╯

Remove one of the two members. The record a reader gets is the one the FIRST key made, so the second is what the help points at.

Taught on: Records › When the compiler refuses a record

reserved-type-name

Error. A declaration takes the name Self. Inside a protocol, Self names the type that conforms to it, so no declaration may use it.

[reserved-type-name]
Error: 'Self' is a reserved Type name
   ╭─┤ Self.es:2:7 │
   │
 2 │     type Self = { name: String }
   │          ──┬─  
   │            ╰─── this name is taken
   │ 
   │ Help: Choose another name.
   │ 
   │ Note: 'Self' is what a Protocol calls the Type conforming to it, so no Type may be declared under it.
───╯

Choose another name. Every form that declares a TYPE is held to this: a type alias, a generic parameter, a choice, a protocol and a namespace. A constant, a function, a case or a member of the name compiles — none of them is a type. A protocol is the one the name is reserved for — every signature inside one may say Self, meaning the type conforming, and a protocol of that name stands where the word resolves.

use-before-declaration

Error. A top-level statement uses a namespace that is declared further down. A namespace exists from the line it is written on.

[use-before-declaration]
Error: Namespace 'Loud' is used before it is declared
   ╭─┤ Loud.es:2:26 │
   │
 2 │     Terminal.print("hello"::shout())
   │                             ──┬──  
   │                               ╰──── this Method comes from it
   │ 
 4 │     namespace Loud for String {
   │               ──┬─  
   │                 ╰─── declared here, below the use
   │ 
   │ Help: Move the Declaration of 'Loud' above this Statement, or this Statement below it.
   │ 
   │ Note 1: A Namespace comes into being where it is written, so nothing that runs above it can reach it.
   │ Note 2: A Function's or a Method's body is not run where it is written, so a body may name a Namespace declared below it.
───╯

Move the namespace above the statement, or the statement below the namespace. The help offers only the moves that leave nothing read before it is declared and keep the order of what the program prints, and names the declarations that must move along. Where no move keeps that order, it says what moving the namespace changes. A function or method body may name a namespace declared below it, because a body runs only when it is called. A statement that calls such a body above the namespace is refused at the call. So is one that hands a function to code that may call it at once, such as map, or calls a function value it may have reached, such as a parameter or a record member. Holding a function, or storing it in a record or a list, runs nothing and is not refused.

Work put in flight with start runs up to its first complete at once, and the rest when the top level next waits: at the first statement from the starting one on that holds a complete. Where that rest uses a namespace declared further down, the label reads “this starts work that later reaches it”. The starting statement is judged as a whole, so a complete anywhere in it counts, even one written to the left of the start: both(complete pause(), start later()) is refused although pause is over before later begins. Write that complete in a statement of its own above, as in constant paused = complete pause(), and pass paused on. Asynchrony › Started work and what comes below says why.

Quick Fix: Move this Statement below ‘Loud’, where the help offers that move.

Taught on: Namespaces and methods › Where a namespace can be used

shadowing-after-read

Error. A block declares a name it already read from outside. Above the declaration the read reached the outer one, and below it the name means the block’s own, so one name would mean two things in one block.

[shadowing-after-read]
Error: 'rate' is declared after this block read another 'rate'
   ╭─┤ Shadow.es:6:12 │
   │
 2 │     constant rate = 2
   │              ──┬─  
   │                ╰─── the outer 'rate'
   │ 
 5 │        constant base = amount::multiply(with rate)
   │                                              ──┬─  
   │                                                ╰─── this read reaches the outer 'rate'
 6 │        constant rate = 3
   │                 ──┬─  
   │                   ╰─── declared here, so 'rate' names this one throughout the block
   │ 
   │ Help: Give this declaration a name of its own, and rename the reads of it that follow, so the outer 'rate' stays the one read above.
   │ 
   │ Note: A name means one thing throughout a block, so a block that reads an outer name can not declare its own of that name.
───╯

Give the block’s own declaration a name of its own, and rename the reads that follow it. A read counts wherever it stands in the block: inside a nested if, a match arm, or a function literal written above the declaration, which would otherwise read the block’s own name when it runs. A parameter’s default is no read of the body, since it is worked out before the body runs, and a match arm’s where guard is no read of the arm’s body for the same reason. An assignment to the outer name counts as a read. A block that declares its own name first and reads it after is fine: that is shadowing, and the outer name is back after the closing brace.

Taught on: Conditions › A block is a scope

unknown-name

Error. A name is used that nothing in scope declares. The Help suggests the closest name when there is one. A word between braces in a string lands here too, since it is read as a name in a hole: "use { and } carefully" reports 'and' is not declared, with a note saying so and the help Write '\{' and '\}' where the braces stand for themselves. That help comes LAST where anything else was found: a hole holding a name one edit from a constant is a hole somebody meant to open and mistyped, while a hole holding a word nothing resembles is prose that was never meant to be read.

A name that is a case of a choice in scope is answered here rather than left to the near miss: the notes name every choice that declares it, and the fix writes the # in front of it. A JavaScript operator or keyword is answered by operator-not-supported or foreign-syntax instead.

A name a namespace reaches is answered here too, and before the near miss. A static is reached as Namespace.name inside its own namespace as well as outside it, so this is the report a bare noon gets one line under static noon:

[unknown-name]
Error: 'noon' is not declared
   ╭─┤ Clock.es:6:24 │
   │
 6 │          <- @::isGreaterThan(noon)
   │                              ──┬─  
   │                                ╰─── no such Variable or Constant
   │ 
   │ Help: Write 'Clock.noon'.
   │ 
   │ Note: A static is reached through its Namespace, inside the Namespace too.
───╯

The same holds for a static method called bare (make(1) is Clock.make(1)), for a method the value in hand answers (isAfterNoon() is @::isAfterNoon(), and a protocol’s provided method is reached the same way), and for a member of the receiver’s record type (width is @.width). Each of those is read off the @ that is actually in hand: inside a match arm that is the value matched, so a method of the enclosing namespace is not offered through it there.

Outside every namespace, one namespace in scope declaring the static is named with a fix, and several are listed with none — Number.Pi answers a bare Pi this way. A name that is also one edit from something in scope is answered with that name first, and the namespace second: head, written under a constant heads, is Did you mean 'heads'? and then Or write 'Http.head'.

[unknown-name]
Error: 'nmae' is not declared
   ╭─┤ Greeting.es:4:17 │
   │
 4 │     Terminal.print(nmae)
   │                    ──┬─  
   │                      ╰─── no such Variable or Constant
   │ 
   │ Help: Did you mean 'name'?
───╯

Fix the spelling, declare the name, or import it.

A namespace specifier that names nothing in scope, the Name of value::<Name>method(), lands here too, at the specifier. Its label reads no such Namespace. Its help offers the import of a namespace another module exports under that name, or else the closest namespace in scope, and dropping the specifier is the other help.

Quick Fix: Change to ‘name’. A name that a module in the workspace exports also gets a fix that imports it, and one that names a case gets Write ‘#Red’ instead of ‘Red’ above both. A name a namespace reaches gets Write ‘Clock.noon’ instead of ‘noon’ and no spelling fix: the name is not what went wrong. Where the name is a record literal’s shorthand it is the member as well as its value, so those fixes spell the member out — Write ‘head = Http.head’ instead of ‘head’, Write ‘Red = #Red’ instead of ‘Red’ — because { Http.head } and { #Red } are not records.

Taught on: Functions › Scope and hoisting

default-references-later-parameter

Error. A parameter’s default reads a parameter declared after it. A default may read the parameters to its left.

[default-references-later-parameter]
Error: 'end' is declared after the Parameter whose default reads it
   ╭─┤ Range.es:2:38 │
   │
 2 │     function span(from start: Integer = end, to end: Integer) -> Integer {
   │                                         ─┬─     ─┬─  
   │                                          ╰───────│─── read here
   │                                                  │   
   │                                                  ╰─── declared here
   │ 
   │ Help: Move 'end' before the Parameter whose default reads it, or write the value out.
   │ 
   │ Note: A default may read `@`, the Parameters to its left, and anything the Declaration is written inside.
───╯

Move the parameter it reads in front, as in span(to end: Integer, from start: Integer = end), or write the value out.

Taught on: Functions › Default values

default-references-own-parameter

Error. A parameter’s default reads the parameter it belongs to.

[default-references-own-parameter]
Error: 'times' is the Parameter its own default is written on
   ╭─┤ Repeat.es:2:51 │
   │
 2 │     function repeat(_ text: String, times: Integer = times) -> String {
   │                                     ──┬──            ──┬──  
   │                                       ╰────────────────│──── this is the Parameter
   │                                                        │    
   │                                                        ╰──── read here
   │ 
   │ Help: Write the value out.
   │ 
   │ Note: A Parameter is bound to the value its default works out, so the default can not read it.
───╯

Write the value out, times: Integer = 1, or rename the parameter.

Taught on: Functions › Default values

default-references-pattern-binding

Error. A default reads a name that a pattern in the same parameter list binds. Pattern names are bound when the body starts, and every default is worked out before that.

[default-references-pattern-binding]
Error: 'width' is bound by a Pattern and can not be read by a default
   ╭─┤ Area.es:2:92 │
   │
 2 │     function area(of { width, height }: { width: Integer, height: Integer }, scale: Integer = width) -> Integer {
   │                        ──┬──                                                                  ──┬──  
   │                          ╰──────────────────────────────────────────────────────────────────────│──── bound by this Pattern
   │                                                                                                 │    
   │                                                                                                 ╰──── read here
   │ 
   │ Help: Read the member off the Parameter itself, or write the value out.
   │ 
   │ Note: A Pattern's bindings are Constants at the head of the body, and every default is worked out before the body runs.
───╯

Name the parameter instead of taking it apart with a pattern, the way JavaScript destructures an object, and read the member off it: area(of size: { width: Integer, height: Integer }, scale: Integer = size.width).

Taught on: Patterns › In a parameter

unknown-type

Error. A type is named that nothing declares. JavaScript’s number is a common cause; Essence’s everyday number types are Integer, Rational and Number.

[unknown-type]
Error: Type 'number' is not declared
   ╭─┤ Count.es:2:18 │
   │
 2 │     constant count: number = 1
   │                     ───┬──  
   │                        ╰──── no such Type
   │ 
   │ Help: Did you mean 'Number'?
───╯

Fix the spelling, declare the type, or import it.

Quick Fix: Change to ‘Number’ when a type name is close, or an import from the module that exports it.

Taught on: Coming from JavaScript › Numbers

unknown-protocol

Error. A bound or a conformance clause names a protocol that nothing declares.

[unknown-protocol]
Error: Protocol 'Comparible' is not declared
   ╭─┤ Largest.es:2:31 │
   │
 2 │     function first<infer Item is Comparible>(_ items: List<Item>) -> Integer {
   │                                  ─────┬────  
   │                                       ╰────── no such Protocol
   │ 
   │ Help: Did you mean 'Comparable'?
───╯

Fix the spelling or import the protocol. Where a module the file reaches declares it, the Help names that module, 'Sized' is declared in Sized.es — import it here., and a Quick Fix writes the entry. Where the file binds that name already, the Help asks for the import under a name of its own.

A refused bound asks nothing of the calls it reaches. The type parameter’s own calls to bounded functions are not refused over it a second time.

Quick Fix: Change to ‘Comparable’ when a protocol name is close.

Taught on: Protocols › Declaring a protocol

unknown-member

Error. A record or case has no member of that name. The Note lists the members it has.

[unknown-member]
Error: { x: Integer, y: Integer } has no member 'z'
   ╭─┤ Point.es:4:23 │
   │
 4 │     Terminal.print(point.z)
   │                          ▲  
   │                          ╰── no such member
   │ 
   │ Note: { x: Integer, y: Integer } has 'x', 'y'.
───╯

Use one of the listed members.

A bare member in a pattern that no arm of the value declares lands here too, at the member, in a case as in a declaration or a parameter. Over Click | KeyPress, case { kye } is refused with Did you mean 'key'?, and a second Help offers writing its type where a record could carry the member. A case naming a member only some arms carry is fine: that is how a match tells the arms apart. So is a member written with its type, as in case { label: String }: a record may carry members its type leaves out, so that is a test the value may pass.

A misspelt member in a case’s payload pattern is read against the payload where the payload holds its near miss and the one member’s value does not. So case #Circle({ radus }) is refused as 'Shape#Circle' has no member 'radus', with Did you mean 'radius'? and a Quick Fix that writes radius as radus, so the body’s reads of radus still resolve. Where the one member holds a record with the near miss, as centre: { x: Integer, y: Integer } does for { xx }, the report names that record and offers x.

Quick Fix: Change to ‘x’ when a member name is close.

Taught on: Records › When the compiler refuses a record

type-without-members

Error. A . looks up a member on a value that has none. Only records, cases and namespaces have members. Everything else is reached through methods, with ::.

[type-without-members]
Error: This value has no members to look up
   ╭─┤ Character.es:4:17 │
   │
 4 │     Terminal.print(text.charAt(0))
   │                    ──┬─  
   │                      ╰─── this is a String
   │ 
   │ Note 1: Only Records, Cases and Namespaces have members.
   │ Note 2: Searched Namespace 'String'.
───╯

A value with no members at all has nothing behind the ., so a method is what the name can have been. Where the value’s type has a method of that name the report is method-called-with-dot instead. Where none is close, as for charAt, there is no help, and a note names the namespaces searched, as unknown-method does. Where one is a near miss, the help spells the call, for a member that was called and for one that was only read. A call keeps its arguments, so it is offered only a method that accepts as many:

[type-without-members]
Error: This value has no members to look up
   ╭─┤ Spelling.es:4:17 │
   │
 4 │     Terminal.print(text.lenght)
   │                    ──┬─  
   │                      ╰─── this is a String
   │ 
   │ Help: Write '::length()' in place of '.lenght' — a Method is called, never read.
   │ 
   │ Note: Only Records, Cases and Namespaces have members.
───╯

A union has no members either, but one of its members may. Only @ in a match arm is narrowed, so on an A | B where A declares x, v.x is answered Read '@.x' in a Match arm that narrows the value — 'case A { … }'. A record that no name in the file binds, as one declared in a module it does not import, is written by its shape, case { x: Integer }, and a case of such a choice is written bare, case #Circle. A pattern such as constant { length } = text writes no ., so its help says to bind the whole value and call ::length() on it instead.

The String method for a character at a position is character(at:).

Taught on: Method calls › Statics and the dot

method-called-with-dot

Error. A method was reached with the . of a member. Methods live in namespaces rather than in the values they work on, so :: reaches one.

[method-called-with-dot]
Error: 'length' is a Method, not a member
   ╭─┤ Length.es:4:22 │
   │
 4 │     Terminal.print(text.length)
   │                    ──┬─ ───┬──  
   │                      ╰─────│──── this is a String
   │                            │    
   │                            ╰──── a Method is reached with '::'
   │ 
   │ Help: Write '::length()' in place of '.length' — a Method is called, never read.
   │ 
   │ Note: Methods live in Namespaces rather than in the values they work on, so '::' reaches one and '.' reads a member a Record or a Case declares.
───╯

The method is there; only the separator is wrong. A member that was read rather than called — text.length rather than text.length() — is told so too, since a method is called and never read.

Quick Fix: Call it with ‘::’. It writes the :: and, where the method was read and takes no arguments, the () behind it.

Taught on: Method calls › Statics and the dot

Types

A value or call that does not fit its type, a function that does not return, and a type written in a way the compiler refuses.

assignment-type-mismatch

Error. A value does not fit the declared type of the constant or variable it is assigned to. The report also points at the declaration when it is in the same file.

[assignment-type-mismatch]
Error: This value does not fit Variable 'count'
   ╭─┤ Count.es:4:10 │
   │
 2 │     variable count = 0
   │              ──┬──  
   │                ╰──── declared as Integer here
   │ 
 4 │     count = "ten"
   │             ──┬──  
   │               ╰──── this is a String
───╯

Assign a value of the declared type, or change the declaration’s type.

Asynchrony adds three Helps under this code. A Future standing where its value is wanted asks for complete, and so does a Started, which is still in flight; the Quick Fix Wait for it with ‘complete’ writes the word for either. A plain value where a future is wanted asks for one to be built — Async.deferred(…), map or andThen.

A variable declared from an empty [] or [=] carries a slot nothing has decided, and a write that would leave it undecided is refused rather than let through. A value that can decide the slot always does, so what reaches this report is a write that cannot — and List<Unknown> on the expected side is a blank, not a type. That is what the Note and Help are there to say: the Note explains the label, and the Help spells the annotation that would decide the blank at the depth it sits — 'variable rows: List<List<Integer>>' for a variable declared as [[]], 'variable box: { items: List<Integer> }' where the blank is a record’s member, 'variable x: List<Integer> | String' where it is one arm of a union.

The same pair is added wherever else a blank can be the expected side: partial-type-mismatch for a record update, return-type-mismatch for a <- or a define arm inside a function literal whose return type was inferred, and payload-type-mismatch for a case built from a generic choice applied to one. They are said only about the blank that did the refusing: a type can hold a blank the refused value never met, and nothing is said about that one.

Taught on: Programs and values › Constants and variables

argument-type-mismatch

Error. An argument does not fit its parameter’s type. The Note gives the type the parameter takes.

[argument-type-mismatch]
Error: This Argument does not fit Parameter 1
   ╭─┤ Greet.es:6:23 │
   │
 6 │     Terminal.print(greet(42))
   │                          ─┐  
   │                           ╰── this is an Integer
   │ 
   │ Note: Parameter 1 is String.
───╯

Pass a value of that type: greet("Ada").

A record literal written as the argument may name only the members the parameter’s type declares, at every level its literals reach, as a literal written anywhere a type is declared may. describe({ x = 1, y = 2, label = "start" }) against a Point is this code, with the label 'label' is not a member of Point and the help Remove 'label'.. A record value passed along still carries what it holds: describe(start) compiles whatever start carries beside x and y. A parameter of type {} takes any record.

Quick Fix: Remove ‘label’, which takes the member out with its comma.

Asynchrony adds the same three Helps this code carries at a constant. A Future passed where its value is wanted asks for complete, and so does a Started, which is still in flight; the Quick Fix Wait for it with ‘complete’ writes the word for either. A plain value where a future is wanted asks for one to be built.

Taught on: Functions › Labels

incomplete-record-argument

Error. A record argument leaves out a member that the parameter’s default does not fill in. A partial default such as options: Options = { retries = 3 } lets a call leave out retries, and every other member must be written.

[incomplete-record-argument]
Error: This Argument is missing 1 member the default does not fill in
   ╭─┤ Connect.es:8:31 │
   │
 8 │     Terminal.print(connect(using { host = "example.com" }))
   │                                  ────────────┬───────────  
   │                                              ╰───────────── 'port' not written here
   │ 
   │ Help: Write 'port' into this Record.
   │ 
   │ Note 1: Parameter 'using' is Options.
   │ Note 2: Its default fills in 'retries'; every other member must be written.
───╯

Write the missing member: connect(using { host = "example.com", port = 443 }).

Quick Fix: Write the missing member ‘port’, or Write the missing members when several are missing.

Taught on: Records › Record parameters with defaults

argument-label-mismatch

Error. An argument’s label does not match its parameter: a different label, a missing one, or one where the parameter takes none.

[argument-label-mismatch]
Error: This Argument is labelled where Parameter 1 takes no label
   ╭─┤ Greet.es:6:26 │
   │
 6 │     Terminal.print(greet(to "Ada"))
   │                             ──┬──  
   │                               ╰──── this is labelled 'to'
   │ 
   │ Help: Pass the value with no label.
   │ 
   │ Note: The signature takes 1 Argument: Parameter 1 is String.
───╯

Write the labels the signature declares, in its order. The Note lists the signature. Terminal.print(items[0]) used to land here, since items read as a label and [0] as the list it labelled; it is foreign-syntax now, reported at the brackets.

Quick Fix: Remove the label. A missing or a different label gets the fix that writes or changes it.

Taught on: Functions › Labels

argument-count-mismatch

Error. A call passes more or fewer arguments than the signature declares.

[argument-count-mismatch]
Error: This call passes the wrong number of Arguments
   ╭─┤ Greet.es:6:17 │
   │
 6 │     Terminal.print(greet("Ada", "Grace"))
   │                    ──────────┬──────────  
   │                              ╰──────────── passes 2 Arguments
   │ 
   │ Note: The signature takes 1 Argument: Parameter 1 is String.
───╯

Pass the arguments the Note lists.

Taught on: Functions › Labels

default-type-mismatch

Error. A parameter’s default is not a value of the parameter’s type.

[default-type-mismatch]
Error: This default does not fit Parameter 'times'
   ╭─┤ Repeat.es:2:51 │
   │
 2 │     function repeat(_ text: String, times: Integer = "twice") -> String {
   │                                                      ───┬───  
   │                                                         ╰───── this is a String
   │ 
   │ Help: Write a value of Type Integer.
   │ 
   │ Note: Parameter 'times' is Integer.
───╯

Write a default of the declared type: times: Integer = 2.

Taught on: Functions › Default values

return-type-mismatch

Error. A <- returns a value that does not fit the declared return type. A define arm that does not fit the define’s type reports this code too.

[return-type-mismatch]
Error: This value does not fit the declared return Type
   ╭─┤ Half.es:3:6 │
   │
 3 │        <- "half"
   │           ───┬──  
   │              ╰──── this is a String
   │ 
   │ Note: The Function returns Integer.
───╯

Return a value of the declared type, or change the declared type.

Asynchrony adds three Helps under this code, and a define arm that answers the wrong type reports under it too. A future returned where the value is wanted asks for complete; so does a Started, which is still in flight; the Quick Fix Wait for it with ‘complete’ writes the word for either. A bare value returned from a body declared -> Future<…> that completes nothing says the body has to build a future — Async.deferred, map or andThen — which is not an edit anything can write for you.

Taught on: Functions › Returning with <-

condition-not-boolean

Error. An if condition or a define condition is not a Boolean. Essence has no truthiness.

[condition-not-boolean]
Error: An If Condition has to be a Boolean
   ╭─┤ Count.es:4:5 │
   │
 4 │     if count {
   │        ──┬──  
   │          ╰──── this is an Integer
   │ 
   │ Help: Ask a question that answers a Boolean — '::isGreaterThan(0)' reads an Integer.
   │ 
   │ Note: Essence has no truthiness — only a Boolean can be a Condition.
───╯

Ask a question that returns a Boolean: if count::isGreaterThan(0) { … }. The help names one the value’s own type has — ::hasValue() for an optional, ::hasCharacters() for a string, ::hasItems() for a list. A function has no question of its own, so the help calls it: if ready() for one that returns a Boolean, and count(…)::isGreaterThan(0) for one that returns an Integer. A future that answers a Boolean is waited for: the help adds complete, and in a body that cannot wait it says to declare the function -> Future<…> first. Reaching through with ::map would answer another future, which no condition takes. A future of anything else is waited for on a line of its own, constant answered = complete …, and answered is asked the question. A union of types of different kinds has no one question, so the help asks each member its own in a match that returns a Boolean. A type parameter answers ::is(…) only where it is bounded by Equatable, so an unbounded one gets no help. The help is left out wherever no question would compile: a function or a future answering such a union, a union whose members a match cannot tell apart, such as List<Integer> | List<String>, a record holding a function, and a choice the file does not import, whose ::is it cannot reach. A record the file does not name is matched by its shape, case { x: Integer }. A static method or a function held in a record is called by the name the condition wrote: if Checks.ready().

Taught on: Conditions › The condition is a Boolean

constant-reassignment

Error. A name that is not a variable is assigned a new value: a constant, a function, a namespace, a parameter, an imported name, or the name of a type, a choice or a protocol.

[constant-reassignment]
Error: 'total' can not be reassigned
   ╭─┤ Total.es:4:2 │
   │
 2 │     constant total = 1
   │              ──┬──  
   │                ╰──── declared as a Constant here
   │ 
 4 │     total = 2
   │     ──┬──  
   │       ╰──── assigned to here
   │ 
   │ Help: Declare it with 'variable' instead of 'constant' if it needs to change.
───╯

Declare it with variable if it needs to change, or bind the new value to a new constant. Only a name declared with constant can become a variable, so any other name is offered the second fix alone: Help: Declare the new value under a name of its own, with 'constant' or 'variable'.

Quick Fix: Declare ‘total’ as a Variable.

Taught on: Programs and values › Constants and variables

missing-return

Error. A path through a function with a return type reaches the end without a <-. An if without an else is the usual cause.

[missing-return]
Error: Not every path through this Function returns
   ╭─┤ Sign.es:2:2 │
   │
 2 │ ╭─▶     function sign(of number: Integer) -> String {
   ┆ ┆   
 6 │ ├─▶     }
   │ │           
   │ ╰─────────── this path falls off the end
   │ 
   │ Help 1: Write a '<-' answering a String at the end of the body.
   │ Help 2: Or give every branch one — an 'if' with no 'else' leaves the path around it falling through.
   │ 
   │ Note: The declared return Type is String, so every path must yield one.
───╯

Return on every path, for example with the else branch: if … { <- "negative" } else { <- "not negative" }.

Quick Fix: Add an else branch to fill in — it writes the branch and leaves the value to you, so this report stays until you write one. The title says so: the fix moves the hole into the open rather than closing it.

Taught on: Functions › Every path returns

infinite-recursion

Error. A method returns a call to itself on every path, so it can never return.

[infinite-recursion]
Error: This Method calls itself on every path, so it can never return
   ╭─┤ Countdown.es:3:3 │
   │
 3 │        forever() -> Integer {
   │        ───┬───  
   │           ╰───── this Method
 4 │          <- @::forever()
   │             ──────┬─────  
   │                   ╰─────── returns a call to the same Method
   │ 
   │ Help: Give it a path that returns without calling itself — a 'match' Case that dispatches to a different Method, or a guard that answers a base value.
   │ 
   │ Note: Every returning path hands back another call to it, so there is no base case to stop the recursion.
───╯

Give it a path that returns without calling itself, such as if @::isLessThanOrEqualTo(0) { <- 0 } else { <- @::subtract(1)::toZero() }.

recursive-type-declaration

Error. A type alias or a choice names itself, directly or through other declarations, or a refinement’s predicate depends on itself. Recursive type declarations are refused.

[recursive-type-declaration]
Error: Type 'Node' names itself
   ╭─┤ Node.es:2:38 │
   │
 2 │     type Node = { value: Integer, next: Node }
   │                                         ──┬─  
   │                                           ╰─── this names the declaration being made
   │ 
   │ Help: Recursive Type declarations are not part of the language yet — break the cycle.
   │ 
   │ Note: A Type declaration is substituted wherever it is named, so a declaration that names itself would never finish resolving.
───╯

A choice that names itself reports the same code, with Choice 'Tree' names itself and the same note.

Break the cycle. A List does not break it: a member typed List<Node> still names Node, and reports this code too. To hold a tree, keep its nodes in a list and give each node the positions of its children in that list, as in type Node = { value: Integer, children: List<Integer> }. Or key the nodes in a dictionary.

A refinement’s predicate reports the same code when reading it would check a value against that same refinement, directly or through others. Here isBelow takes a High and isAbove takes a Low, so neither predicate can be read before the other:

[recursive-type-declaration]
Error: The predicate of 'Low' depends on itself through 'High'
    ╭─┤ RecursiveTypes.es:46:27 │
    │
 46 │     type Low = Integer where @::isBelow(5)
    │                              ──────┬──────  
    │                                    ╰──────── reading this checks a value against 'High'
    │ 
    │ Help: Break the cycle, so that no predicate checks a value against a refinement that depends on it.
    │ 
    │ Note 1: 'Low' depends on 'High', which depends on 'Low' again.
    │ Note 2: Reading a predicate typechecks it, so one that checks a value against its own refinement, directly or through others, can never be read.
────╯

High reports the same, through Low. Had isBelow taken a Low, the report would read The predicate of 'Low' depends on itself, with only the second note. Give the methods parameters of the base type, isBelow(_ limit: Integer) and isAbove(_ limit: Integer), and both predicates can be read.

Taught on: Unions and type aliases › An alias is not a new type

top-level-return

Error. A <- is written outside every function.

[top-level-return]
Error: There is nothing here to return from
   ╭─┤ Answer.es:2:2 │
   │
 2 │     <- 42
   │     ──┬──  
   │       ╰──── this is outside any Function
   │ 
   │ Help 1: Drop the '<-' and write the value on its own, or as a 'constant'.
   │ Help 2: Or move the Statement into a Function, which is the only thing a '<-' answers for.
───╯

Remove the <-, or move the code into a function.

Taught on: Functions › Returning with <-

not-a-function

Error. A call is written on a value that is not a function.

[not-a-function]
Error: This Expression is not a Function
   ╭─┤ Total.es:4:17 │
   │
 4 │     Terminal.print(total())
   │                    ──┬──  
   │                      ╰──── this is an Integer
   │ 
   │ Help 1: Remove the '()' — the name already reads the value.
   │ Help 2: Or call a Method on it with '::', which is how a Method is reached.
───╯

Remove the parentheses, or call a function. A namespace is never called, and the help builds a value of its type instead: String(5) is answered with 5::toString(), Integer(5) with 5 alone, and List(1, 2) with the list literal [1, 2]. A static method is offered only where it answers that type, or wraps it in a choice such as an optional where the position takes one: Integer("5") is answered with Integer.parse("5"), which answers an Optional<Integer>.

Taught on: Functions as values › Storing and returning functions

path-step-not-a-record

Error. A step of a member path reads a member off something that is not a record, such as .tags.length where tags is a list. Only a record or a case has members a path can step through.

[path-step-not-a-record]
Error: A member path steps through Records only
   ╭─┤ Tags.es:2:55 │
   │
 2 │     constant counts = [{ tags = ["a", "b"] }]::map(.tags.length)
   │                                                          ───┬──  
   │                                                             ╰──── read off a List<String>
   │ 
   │ Help: Write the Function literal instead, and decide the value the way its Type asks to be decided.
   │ 
   │ Note: Only a Record or a Case has members a path can step through. An Optional, a Union, a Choice or a List is decided before it is read, and deciding it is a Match rather than a dot.
───╯

Write a function literal and call the method there: (entry) { <- entry.tags::length() }.

Taught on: Functions as values › Member paths

path-key-outside-combination

Error. A dotted key is written in a record literal that updates nothing, as in { server.port = 8080 }. A path reaches into a value that is already there.

[path-key-outside-combination]
Error: A path key reaches into nothing here
   ╭─┤ Config.es:4:29 │
   │
 4 │     constant blank: Config = { server.port = 8080 }
   │                                ─────┬─────  
   │                                     ╰─────── this reaches into a value
   │ 
   │ Help 1: Write the whole member: 'server = { … }'.
   │ Help 2: Or update a value that already has it: '{ original with server.port = … }'.
   │ 
   │ Note: A Record Literal writes its members from nothing, so there is no value under this key to reach into. A path key needs one that is already there — the value a 'with' updates, or the value a default fills in for an Argument or a Case payload.
───╯

Write the whole member, { server = { host = "db", port = 8080 } }, or update a value that has it: { config with server.port = 8080 }. A dotted key written with no value in such a literal, { server.port }, is reported the same way, since it reaches into nothing either.

Taught on: Records › When the compiler refuses a record

path-key-without-default

Error. A path key in an argument reaches into a member that the parameter’s default does not fill in, so there is nothing under it to merge with.

[path-key-without-default]
Error: A path key reaches into a member no default fills in
   ╭─┤ Connect.es:9:33 │
   │
 9 │     Terminal.print(connect(using { server.port = 1 }))
   │                                    ───┬──  
   │                                       ╰──── nothing fills in 'server'
   │ 
   │ Help: Write the whole member: 'server = { … }'.
   │ 
   │ Note 1: Parameter 'using' is Options.
   │ Note 2: Its default fills in 'retries', and 'server' is not one of them — so there is nothing under this key to merge with.
───╯

Write the whole member: connect(using { server = { host = "db", port = 1 } }).

Taught on: Records › Record parameters with defaults

path-on-computed-value

Error. An update with a dotted key is written on a value computed on the spot, as in { load() with server.port = 8080 }. A path reads its base once per level, so the base must be a name.

[path-on-computed-value]
Error: A path key updates a value it can name
   ╭─┤ Config.es:6:22 │
   │
 6 │     constant config = { load() with server.port = 8080 }
   │                         ───┬──  
   │                            ╰──── this is worked out here, not named
   │ 
   │ Help 1: Bind it to a Constant first, and update the Constant.
   │ Help 2: Or write the nesting out by hand, so the value is worked out once.
   │ 
   │ Note: A path reaches into the value one level at a time, so the value is read once for each level it reaches through. A name, '@', or a chain of member reads over one of those reads the same value every time; anything worked out on the spot would be worked out again for each level.
───╯

Bind the value to a constant first, constant loaded = load(), and update that: { loaded with server.port = 8080 }.

Taught on: Records › When the compiler refuses a record

uncombinable-types

Error. A with update is written on a value that cannot be updated, such as an Integer. The Note lists what can.

[uncombinable-types]
Error: Integers can not be combined
   ╭─┤ Answer.es:3:23 │
   │
 3 │     constant changed = { answer with port = 1 }
   │                          ───┬──  
   │                             ╰──── this is an Integer
   │ 
   │ Note: Only Records, Namespaces and Dictionaries can be combined.
───╯

Update a record or a dictionary.

Taught on: Records › When the compiler refuses a record

wrong-update-brackets

Error. An update uses the wrong brackets for its base. A record is updated in braces, { config with port = 2 }, and a dictionary in brackets, [ages with "alex" = 40].

[wrong-update-brackets]
Error: A key that is a value belongs to a Dictionary
   ╭─┤ Ages.es:3:31 │
   │
 3 │     constant older = { ages with "alex" = 40 }
   │                                  ───┬──  
   │                                     ╰──── this key is a value, not a member name
   │ 
   │ Help 1: Write the update in brackets: '[base with "a" = 1]'.
   │ Help 2: Or name the member, if a Record is what was meant: '{ base with a = 1 }'.
   │ 
   │ Note: Braces update a Record, whose keys are the member names it declares. A key that is a value is a Dictionary's, and a Dictionary is updated in brackets.
───╯

Swap the brackets.

Quick Fix: Write the update in brackets or Write the update in braces, when the report underlines the whole update. { ages with more } on a dictionary gets one, and so does [point with x = 3] on a record. A value key in braces, as above, gets none.

Taught on: Dictionaries › Setting and removing entries

duplicate-key

Error. A dictionary literal writes the same key twice. The second entry would replace the first without a trace.

[duplicate-key]
Error: This key is written twice
   ╭─┤ Ages.es:2:30 │
   │
 2 │     constant ages = ["kim" = 7, "kim" = 8]
   │                      ──┬──      ──┬──  
   │                        ╰──────────│──── first written here
   │                                   │    
   │                                   ╰──── written a second time here
   │ 
   │ Help: Keep one entry for the key.
   │ 
   │ Note: A Dictionary holds one value per key, so the second entry would take the first one's place and nothing would say the first was ever there.
───╯

Keep one entry per key.

Quick Fix: Remove this entry.

Taught on: Dictionaries › Writing a dictionary

partial-type-mismatch

Error. An update sets a member the original does not have, or gives a member a value of another type. A dictionary update is held to its key and value types the same way.

[partial-type-mismatch]
Error: This is not a Partial of the value it updates
   ╭─┤ Point.es:3:36 │
   │
 3 │     constant moved = { point with x = "one" }
   │                        ──┬──          ──┬──  
   │                          ╰──────────────│──── this is a { x: Integer, y: Integer }
   │                                         │    
   │                                         ╰──── this is a String, and the value it updates declares an Integer
   │ 
   │ Note: An update may only set members the original already has, with the Types it declared for them.
───╯

Set only members the original has, with their declared types: { point with x = 3 }.

An update is what DECIDES a member the original left undecided, so { box with items = ["a"] } over a box whose items came from [] answers { items: List<String> } and is not refused. What is refused is an update that would leave the slot undecided — items = 1 says nothing about what a list holds — and that report carries the same Note and Help as assignment-type-mismatch, with the shape to annotate spelled out: '{ items: List<Integer> }'.

Taught on: Records › When the compiler refuses a record

wrong-type-argument-count

Error. A generic type is given the wrong number of type arguments.

[wrong-type-argument-count]
Error: List takes exactly 1 Type Argument
   ╭─┤ Items.es:2:18 │
   │
 2 │     constant items: List<Integer, String> = []
   │                     ──────────┬──────────  
   │                               ╰──────────── 2 Type Arguments given
   │ 
   │ Help: Write 'List<…>', with the Type you mean in place of each '…'.
───╯

A generic type named with no arguments at all reports the same code, with the count it takes as a note:

[wrong-type-argument-count]
Error: Type 'Optional' was given the wrong number of Type Arguments
   ╭─┤ Found.es:2:18 │
   │
 2 │     constant found: Optional = #Empty
   │                     ────┬───  
   │                         ╰───── 0 Type Arguments given
   │ 
   │ Help: Write 'Optional<…>', with the Type you mean in place of each '…'.
   │ 
   │ Note: 'Optional' takes 1 Type Parameter.
───╯

Give it as many as it declares: List<Integer>.

Writing none at all is the same mistake, and the same code: Optional, Result, Future, Started and every generic choice are refused when the type arguments are left off entirely. List and Dictionary are the exceptions — a bare List is a list of anything and says so.

Taught on: Generics › A type alias applies its type arguments too

type-not-generic

Error. Type arguments are given to a type that takes none.

[type-not-generic]
Error: This Type takes no Type Arguments
   ╭─┤ Count.es:2:18 │
   │
 2 │     constant count: Integer<String> = 1
   │                     ───────┬───────  
   │                            ╰───────── the Type Arguments have nowhere to go
   │ 
   │ Help: Remove the Type Arguments — 'Integer' stands on its own.
───╯

Remove the type arguments: Integer.

Taught on: Generics › A type alias applies its type arguments too

infer-on-applied-parameter

Error. A choice or a type alias marks a type parameter infer. Their type arguments are written wherever they are used, so there is nothing to infer.

[infer-on-applied-parameter]
Error: A Choice's Type Parameters can not be inferred
   ╭─┤ Holder.es:2:16 │
   │
 2 │     choice Holder<infer Item> {
   │                   ─────┬────  
   │                        ╰────── 'infer' has nothing to do here
   │ 
   │ Help: Remove the 'infer' before 'Item'.
   │ 
   │ Note: A Choice's Type Parameters are applied at every use, never inferred from one.
───╯

Remove infer: choice Holder<Item> { … }.

Quick Fix: Remove ‘infer’.

Taught on: Generics › A choice applies its type arguments

uninferred-namespace-parameter

Error. A namespace declares a type parameter without infer. A namespace works its type parameters out from the receiver of each call.

[uninferred-namespace-parameter]
Error: A Namespace's Type Parameters must be inferred
   ╭─┤ Boxes.es:2:18 │
   │
 2 │     namespace Boxes<Item> for { value: Item } {
   │                     ──┬─  
   │                       ╰─── nothing can ever bind this Parameter
   │ 
   │ Help: Declare it as 'infer Item'.
   │ 
   │ Note: A Namespace's Type Parameters are worked out from the receiver at every call, which is what 'infer' says.
───╯

Write infer: namespace Boxes<infer Item> for { value: Item }.

Quick Fix: Declare it as ‘infer Item’.

Taught on: Generics › A namespace infers from its receiver

uninferred-type-parameter

Error. A function or a method declares a type parameter without infer and without a default. A call writes no type arguments, so only infer lets one bind it. A method’s <Item is Comparable> that bounds its namespace’s own Item is a bound, not a type parameter of the method, and is not refused here. A function written inside a method declares type parameters of its own, so it is held to this like any other.

[uninferred-type-parameter]
Error: Type Parameter 'Item' needs 'infer' or a default
   ╭─┤ Plain.es:2:17 │
   │
 2 │     function plain<Item>(_ item: Item) -> Item {
   │                    ──┬─  
   │                      ╰─── nothing can ever bind this Parameter
   │ 
   │ Help: Write 'infer Item'.
   │ 
   │ Note: A Function's Type Parameters are worked out from the Arguments at every call, which is what 'infer' says, or taken from a default. A call writes no Type Arguments.
───╯

Write infer: function plain<infer Item>(_ item: Item) -> Item. A call to the function is checked as if infer were written, so it reports nothing further.

Quick Fix: Declare it as ‘infer Item’.

Taught on: Generics › Only the arguments bind

zero-denominator

Error. A rational literal has a denominator of zero, such as 1/0.

[zero-denominator]
Error: A Rational can not have a denominator of zero
   ╭─┤ Ratio.es:2:19 │
   │
 2 │     constant ratio = 1/0
   │                      ─┬─  
   │                       ╰─── this divides by zero
───╯

Write a denominator other than zero.

Taught on: Programs and values › Rationals

invalid-refinement-predicate

Error. A checked refinement’s where clause cannot be checked. Either its base cannot be refined, such as Boolean, or the clause asks something other than a method of @ itself, such as the chained @::trim()::hasCharacters(). The bases are Integer, Rational, String, an applied List and an applied Dictionary.

[invalid-refinement-predicate]
Error: A 'where' clause can not refine Boolean
   ╭─┤ Flag.es:2:13 │
   │
 2 │     type Yes = Boolean where @::is(true)
   │                ───┬───  
   │                   ╰───── this is Boolean
   │ 
   │ Help 1: Drop the 'where' clause from 'Yes', which leaves the Alias naming Boolean and nothing more.
   │ Help 2: Or write the refinement on a base one can be checked against — an Integer, a Rational, a String, an applied List or an applied Dictionary.
   │ 
   │ Note: A checked refinement is written on an Integer, a Rational, a String, an applied List or an applied Dictionary — 'List<String>', never a bare 'List'.
───╯

Refine one of those bases with a method called on @: type Small = Integer where @::isLessThan(10). Dropping the clause compiles, and it answers a different declaration — “a Boolean that is true” becomes “any Boolean” — so the help says what that costs and names the bases the intent survives on.

A where clause that is not one call on @ is a different message under the same code — This is not a predicate a refinement can be checked by, with Call the Method on '@' directly. as its help — and a bare List or Dictionary base is a third wording, A 'where' clause can not refine List.

Taught on: Checked refinements › What the predicate may say

predicate-not-boolean

Error. A refinement’s where clause does not return a Boolean.

[predicate-not-boolean]
Error: This predicate is not a Boolean
   ╭─┤ Small.es:2:29 │
   │
 2 │     type Small = Integer where @::absolute()
   │                                ──────┬──────  
   │                                      ╰──────── this is NonNegativeInteger
   │ 
   │ Help: Call a Method on '@' that answers a Boolean — '@::isGreaterThan(0)', for instance.
   │ 
   │ Note: A 'where' clause is a question about the value being refined, so it has to answer 'true' or 'false'.
───╯

Call a method that returns a Boolean: type Small = Integer where @::isLessThan(10).

Taught on: Checked refinements › What the predicate may say

Dispatch

Which method or overload a call reaches, and what its arguments ask of it.

no-matching-overload

Error. The arguments fit none of a method’s overloads. The labels name the argument the closest candidate refused, what it is, and what that candidate takes there; each candidate signature is listed in a Note, with where it first disagreed where that is somewhere else.

[no-matching-overload]
Error: No overload of 'add' accepts these Arguments
   ╭─┤ Add.es:2:17 │
   │
 2 │     Terminal.print(5::add("one"))
   │                       ─┬─ ──┬──  
   │                        ╰────│──── 'Integer::add' takes an Integer as Parameter 1
   │                             │    
   │                             ╰──── this is a String
   │ 
   │ Note 1: 'Integer::add' takes 1 Argument: Parameter 1 is Integer.
   │ Note 2: 'Integer::add' takes 1 Argument: Parameter 1 is Rational.
   │ Note 3: 'Integer::add' takes 1 Argument: Parameter 1 is Algebraic.
   │ Note 4: 'Integer::add' takes 1 Argument: Parameter 1 is Transcendental.
   │ Note 5: 'NonNegativeInteger::add' takes 1 Argument: Parameter 1 is PositiveInteger.
   │ Note 6: And 3 more Overloads of this name, not listed.
───╯

Pass arguments that one of the listed signatures takes: 5::add(1).

One refused argument has an answer of its own: a future written where the value it answers with is wanted. The Help is the one every other position gets — This describes work that has not run — add 'complete'. — and it carries the Quick Fix below.

Quick Fix: Wait for it with ‘complete’, for that argument alone. Nothing is offered for any other refusal: what to pass instead is a judgement.

Taught on: Method calls › When a call fails

ambiguous-namespace

Error. More than one namespace provides the method for this value, and none of them targets it more closely than the others.

[ambiguous-namespace]
Error: 'shout' is provided by more than one Namespace
    ╭─┤ Loud.es:14:17 │
    │
 14 │     Terminal.print("hello"::shout())
    │                             ──┬──  
    │                               ╰──── these Arguments match all of them
    │ 
    │ Help: Name it at the call, e.g. 'value::<Loud>shout(…)'.
    │ 
    │ Note 1: 'Loud' declares 'shout'.
    │ Note 2: 'Louder' declares 'shout'.
────╯

Name the namespace at the call: "hello"::<Loud>shout(). Where two protocols provide the method, name the protocol whose body should run. Where one protocol’s body reaches the value through two namespaces, naming that protocol picks neither. The help then names a protocol only one of the namespaces conforms to, such as a Left that extends it. Where there is none, the help is to drop the conformance from all but one of the namespaces. On a union, a pick holds for every member, so the help names one only where every member answers through it. Otherwise it asks for a match that picks in the arm for the ambiguous member.

A call that names the namespace, such as Books.label(book), reports the same code where two protocols that do not extend each other both provide the method to that namespace, and the call’s arguments fit both. Where they fit one, that protocol’s body runs, as Books.m(book, 3) runs the m that takes an Integer. The message reads 'label' is provided to 'Books' by more than one Protocol, and the help is to call the method on the value with a pick instead: book::<Priced>label().

Quick Fix: Write ‘::<Loud>’ at the call, one for each candidate.

Taught on: Namespaces and methods › Choosing between namespaces

undecided-receiver-type

Error. A method is called on a value whose type is not fully known, such as the empty list [], and several namespaces declare that method.

[undecided-receiver-type]
Error: 'tag' is called on a value whose Type is not fully known here
    ╭─┤ Tag.es:14:17 │
    │
 14 │     Terminal.print([]::tag())
    │                    ─┐  ─┬─  
    │                     ╰───│─── this is a List<Unknown>
    │                         │   
    │                         ╰─── 'tag' is looked up in its Namespaces
    │ 
    │ Help: Annotate what the receiver comes from with 'List<Integer>', for instance, so its Type is decided before the call.
    │ 
    │ Note 1: 'Numbers' declares 'tag'.
    │ Note 2: 'Words' declares 'tag'.
    │ Note 3: List<Unknown> is matched by all of them, so which one runs would be decided by a Type nothing has decided.
────╯

Annotate the value first, constant numbers: List<Integer> = [], and call the method on it: numbers::tag(). The help spells the annotation from the receiver’s own type, so [=]::tag() is told of a Dictionary. A slot nothing decided is filled with an example type, which the help says.

unknown-method

Error. No namespace in scope declares a method of that name for the value’s type. The Note lists the namespaces it searched.

[unknown-method]
Error: No Method named 'shout' for this value
   ╭─┤ Shout.es:2:26 │
   │
 2 │     Terminal.print("hello"::shout())
   │                    ───┬───  ──┬──  
   │                       ╰───────│──── this is a NonEmptyString
   │                               │    
   │                               ╰──── no Method of this name
   │ 
   │ Note: Searched Namespaces 'String', 'NonEmptyString'.
───╯

Fix the spelling, declare the method in a namespace, or import the namespace that has it.

When the value holds something that does have the method, the report says so instead of guessing at a near miss. A list holds its items, a dictionary its values, a case its payload, and a future the value it answers with:

[unknown-method]
Error: No Method named 'add' for this value
   ╭─┤ Totals.es:4:25 │
   │
 4 │     Terminal.print(prices::add(1)::toString())
   │                    ───┬──  ─┬─  
   │                       ╰─────│─── this is a List<Integer>
   │                             │   
   │                             ╰─── no Method of this name
   │ 
   │ Help 1: Call '::add(…)' on each item — '::map((item) { <- item::add(…) })'.
   │ Help 2: Or read one out with '::item(at …, defaultingTo …)' and call '::add(…)' on it.
   │ 
   │ Note 1: 'add' is a Method of Integer, which is what a List<Integer> holds — a Method of its items rather than of the List itself.
   │ Note 2: Searched Namespaces 'List', 'IntegerList', 'NumberList', 'KeyedNumberList', 'GroupedList'.
───╯

The reading method in the second Help is read off the receiver, so a NonEmptyList is offered firstItem() — which answers the item outright — and a plain list is offered item(at:defaultingTo:) instead. A Dictionary gets no ::map Help at all, because its transform is handed a whole { key, value } entry rather than the value on its own.

A forgotten complete is the same mistake with a different answer. complete takes the whole call chain behind it, so the word cannot go in front of the call that was refused, and the Help binds the value first:

[unknown-method]
Error: No Method named 'add' for this value
   ╭─┤ Report.es:8:28 │
   │
 8 │     Terminal.print(fetched()::add(1)::toString())
   │                    ────┬────  ─┬─  
   │                        ╰───────│─── this is a Future<Integer>
   │                                │   
   │                                ╰─── no Method of this name
   │ 
   │ Help 1: Wait for it on a line of its own — 'constant answered = complete …' — and call '::add(…)' on 'answered'.
   │ Help 2: Or reach through it with '::map((value) { <- value::add(…) })', which answers another Future.
   │ 
   │ Note 1: 'add' is a Method of Integer. This describes work that has not run — the Integer is what a Future<Integer> answers with, once something waits for it.
   │ Note 2: 'complete' takes the whole chain behind it, so a 'complete' written in front of this call would wait for the call rather than for the receiver.
   │ Note 3: Searched Namespace 'Future'.
───╯

Written where nothing can wait — inside a body that answers something other than a future — the Help naming the word is withheld, because following it would be refused. A Started reads the same, with “This is still in flight” in place of the first sentence.

On a union receiver the Note also says which members answer the name: 'uppercase' answers for String, and not for Integer.

A near miss is drawn first from the methods whose call this call could have been — the ones whose labels and argument count fit what was written — so a name that would only trade this refusal for the next is not offered. Where none of those is close and the call wrote a label, every method name is measured again, one edit at most: primes::lenght(of 1) is answered Did you mean 'length'?, because the label is a second mistake rather than a reason to say nothing about the name.

Quick Fix: Change to ‘name’ when a method name is close, or an import of a namespace another module exports. No spelling fix is offered where the value holds the answer: the name is not what went wrong.

Taught on: Method calls › When a call fails

no-namespace-for-value

Error. The value’s type has no namespace at all, so it has no methods. An unbounded type parameter is the usual case: nothing is known about Item.

[no-namespace-for-value]
Error: No Namespace provides Methods for this value
   ╭─┤ Show.es:3:6 │
   │
 3 │        <- item::toString()
   │           ──┬─  ────┬───  
   │             ╰───────│───── this is an Item
   │                     │     
   │                     ╰───── 'toString' is looked up in its Namespaces
   │ 
   │ Help: Bound the Type Parameter by a Protocol that declares 'toString' — '<infer Item is Printable>' at the Declaration that introduces it.
   │ 
   │ Note: No Namespace in scope targets Item.
───╯

Bound the type parameter by a protocol that has the method: show<infer Item is Printable>(_ item: Item).

With a namespace specifier, the lookup is limited to the namespace it names, and the note says what that namespace targets. Where Shout is declared for String, 5::<Shout>loud() looks only in Shout, and the note is 'Shout' targets String, which a PositiveInteger is not. Dropping the specifier lets every namespace answer, so the help to drop it is offered only where another namespace answers the method for the value and the call then compiles. Where the arguments do not fit, as in 5::<Orderable>is("a"), the help names the method whose arguments to pass: Help: Drop the Namespace specifier, and pass 'is' the Arguments 'Integer::is' takes. A type parameter’s methods come through its protocol alone, so a specifier naming a namespace finds nothing on one. A protocol pick says which of the value’s conformances answers, and reaches what the protocol provides or inherits through it. A pick of a method the protocol neither declares nor inherits, as 5::<Orderable>is(3), is this code, and so is a pick on a value that does not conform, as "a"::<Orderable>isLessThan("b"). A pick of a method the protocol has no body for is picked-requirement.

Taught on: Generics › A type parameter is opaque

not-a-namespace

Error. The name in a namespace specifier, the Name of value::<Name>method(), is not a namespace where the call is written.

[not-a-namespace]
Error: 'total' is not a Namespace
   ╭─┤ Loud.es:4:27 │
   │
 2 │     constant total = 1
   │              ──┬──  
   │                ╰──── declared here
   │ 
 4 │     Terminal.print("hello"::<total>append("!"))
   │                              ──┬──  
   │                                ╰──── this is an Integer
   │ 
   │ Help: Drop the Namespace specifier, or rename whatever shadows the Namespace.
   │ 
   │ Note: A Method can only be looked up in a Namespace, and 'total' names an Integer here.
───╯

Drop the specifier, as in "hello"::append("!"), or name a namespace there. Where a constant shadows the namespace you meant, rename the constant.

A specifier that names a type lands here too, labelled this names a Type: a type holds no methods of its own, so the help is to drop the specifier. A protocol’s name is a protocol pick instead, and a name nothing declares is unknown-name.

picked-requirement

Error. A protocol pick, the Protocol of value::<Protocol>method(), names a method the protocol declares without a body. A pick calls the body the protocol provides, and a requirement has none: each conforming namespace writes its own.

[picked-requirement]
Error: 'Equatable' has no body for 'is'
   ╭─┤ Fruit.es:2:26 │
   │
 2 │     Terminal.print("pear"::<Equatable>is("plum"))
   │                             ────┬──── ─┐  
   │                                 ╰──────│── this picks 'Equatable'
   │                                        │  
   │                                        ╰── 'Equatable' declares this without a body
   │ 
   │ Help: Drop the pick, or pick the Namespace that writes 'is': '::<String>is(…)'.
   │ 
   │ Note: A pick through a Protocol calls a body the Protocol provides, and 'Equatable' declares 'is' without one: each conforming Namespace writes its own.
───╯

Drop the pick, as in "pear"::is("plum"), or name the namespace that writes the method: "pear"::<String>is("plum"). Where only a derived conformance answers, as on a choice, or each member of a union does, the help is to drop the pick. Dropping it is offered only where the call then compiles. Where the arguments do not fit, as in 5::<Equatable>is("a"), the help names the method whose arguments to pass: Help: Drop the pick, and pass 'is' the Arguments 'Integer::is' takes. Where the namespace writes no such method and two protocols provide it, dropping the pick would tie their bodies. The help then picks the protocol whose body the conformance runs, the one a bound through the picked protocol runs: Help: Pick the Protocol whose body 'Requiring' runs here: '::<Other>trail(…)'. On a union, each member’s method takes its own type, so x::<Equatable>is(x) on an Integer | String asks for a match that calls @::is(@) in each arm. Where no namespace in scope answers it for the value, the help asks for a value whose namespace does, and a namespace another module exports is offered as an import. The protocol is named as the pick spells it, and a requirement it takes from a protocol it extends is put down to that one: 5::<Orderable>compare(to 3) says Comparable declares compare. A pick of a method the protocol provides, such as "pear"::<Equatable>isNot("plum"), is what a pick is for, and on a type parameter bounded by the protocol a pick reaches its requirements too.

Taught on: Protocols › Calling a provided method

undispatchable-method

Error. A method is called on a union whose members cannot be told apart while the program runs, such as a union of two type parameters.

[undispatchable-method]
Error: 'toString' can not be dispatched on this value
   ╭─┤ Describe.es:3:6 │
   │
 3 │        <- value::toString()
   │           ──┬──  
   │             ╰──── this is a First | Second
   │ 
   │ Help: Take one Type Parameter in place of the Union — '<infer Item is Printable>(_ value: Item)' — since Types erase before a Match runs, and a Match is the only thing that narrows.
   │ 
   │ Note: 2 member Types of the Union are indistinguishable at runtime: First, Second.
───╯

Take one type parameter instead of a union of two: describe<infer Item is Printable>(_ value: Item). A match cannot help here — types erase before one runs, so a case naming a type parameter accepts every value that reaches it — and the help offers one only where the union’s members can be told apart at runtime.

untyped-namespace-method

Error. A namespace without a target type, one with no for …, declares an instance method. Such a namespace holds only static methods.

[untyped-namespace-method]
Error: A Namespace without a target Type can only hold static Methods
   ╭─┤ Tools.es:3:8 │
   │
 3 │ ╭─▶        shout() -> String {
 4 │ │            <- "HEY"
 5 │ ├─▶        }
   │ │              
   │ ╰────────────── this Method is not static
   │ 
   │ Help: Give the Namespace a target Type with 'for …', or make the Method static.
───╯

Give the namespace a target type, namespace Tools for String, or mark the method static.

Taught on: Namespaces and methods › Statics and the dot

static-method-on-value

Error. A static method is called on a value with ::. A static method takes no receiver.

[static-method-on-value]
Error: 'origin' is a static Method
    ╭─┤ Point.es:12:23 │
    │
 12 │     Terminal.print(here::origin())
    │                    ──┬─  ───┬──  
    │                      ╰──────│──── this is a Point
    │                             │    
    │                             ╰──── a static Method is called on its Namespace, not on a value
    │ 
    │ Help: Write 'Points.origin(…)' without the value — the signature takes no receiver.
    │ 
    │ Note: 'Points' declares 'origin' as static.
────╯

Call it on its namespace with .: Points.origin(). Inside a refinement’s where predicate, which asks only methods of @, the help asks for the method to be declared without static instead, and no Quick Fix is offered. Where the static takes the value as its first parameter, the help also says to read @ in that parameter’s place, since dropping static alone leaves it among the arguments.

Quick Fix: Write ‘Points.origin(…)’ without the value. A static takes no receiver, so the value the call was written on either belongs among the arguments or does not belong at all, and the signature’s arity decides which — only the shape it accepts is offered, and where both shapes fit the help keeps its hedge and neither fix is preferred.

Taught on: Namespaces and methods › Statics and the dot

indistinguishable-default-parameter

Error. A parameter with a default is followed by a parameter with the same label, or both have no label. A call that passes one argument could mean either.

[indistinguishable-default-parameter]
Error: This default could not be told apart from the Parameter after it
   ╭─┤ Span.es:2:35 │
   │
 2 │     function span(_ start: Integer = 0, _ end: Integer) -> Integer {
   │                                      ▲  ───────┬──────  
   │                                      ╰─────────│──────── this default
   │                                                │        
   │                                                ╰──────── and this Parameter carries no label either
   │ 
   │ Help: Give one of them a label, or move the default to the last of them.
   │ 
   │ Note: An Argument is matched to a Parameter by its label before its Type is read, so a call passing one of them could mean either.
───╯

Give one of them a label, or move the defaulted one last: span(_ end: Integer, from start: Integer = 0).

Taught on: Functions › Default values

ambiguous-overload-default

Error. A default on one entry of an overload block lets it accept exactly the calls another entry accepts.

[ambiguous-overload-default]
Error: This default makes two Overloads accept the same call
   ╭─┤ Greeting.es:4:28 │
   │
 4 │              (times count: Integer = 1) -> String {
   │                                      ▲  
   │                                      ╰── leaving this out takes no Arguments
   │ 
 7 │ ╭─▶          () -> String {
 8 │ │             <- @
 9 │ ├─▶          }
   │ │                
   │ ╰──────────────── this entry takes no Arguments
   │ 
   │ Help: Delete the entry the default already stands for, or give the Parameters labels that tell the two apart.
   │ 
   │ Note: An Overload is selected by the Arguments a call writes, so two entries that accept the same ones can not both be reached.
───╯

Delete the () -> String entry. Without it, "hi"::greet() reaches the first entry with count at 1. Or give the parameters labels that tell the entries apart.

Taught on: Namespaces and methods › Overloads

ambiguous-overload-answer

Error. A function passed to an overloaded call answers a type more than one entry takes: the type its body answers, the answer type a literal writes, or a named function’s answer type. The entry whose answer type every other one takes is selected, and no entry’s answer type is taken by all the others, so the call has more than one reading.

[ambiguous-overload-answer]
Error: More than one Overload takes what this Function answers
    ╭─┤ OverloadAnswers.es:26:34 │
    │
 26 │     constant picked = Picks.pick(on (v) { <- v })
    │                                     ─┬─  
    │                                      ╰─── this answers an Integer, which 'Integer | String' and 'Integer | Boolean' both take
    │ 
    │ Help 1: Write the return Type after the Parameter list — '-> Integer | String', for the entry that answers it.
    │ Help 2: Or write the return Type after the Parameter list — '-> Integer | Boolean', for the entry that answers it.
    │ 
    │ Note: An Overload is selected by the Types its Arguments write, and a Function by what it answers. The entry whose answer every other one takes is selected, and none does here.
────╯

Write the answer type the entry you mean takes: Picks.pick(on (v) -> Integer | Boolean { <- v }). For a named function, pass a literal that calls it and writes that type. A written answer type is the function’s own answer, so the narrowest entry that takes it is selected, even where a wider entry is written first. Where every other entry’s answer type takes one entry’s, as Scalar takes Integer, that entry is selected without a report, whichever entry is written first. The refused call answers nothing to check, so using its answer reports nothing more.

fallback-never-used

Warning. A defaultingTo argument can never be used, because the call without it already returns a value that is never empty. A written list proves it has items, so [3, 1, 2]::firstItem() returns an Integer.

[fallback-never-used]
Warning: This 'defaultingTo' Argument can never be read
   ╭─┤ First.es:2:38 │
   │
 2 │     Terminal.print([3, 1, 2]::firstItem(defaultingTo 0))
   │                                         ───────┬──────  
   │                                                ╰──────── this fallback can never be read
   │ 
   │ Help: Drop the 'defaultingTo' Argument; the call already answers an Integer.
   │ 
   │ Note: Without it the call answers an Integer, which is never empty.
───╯

Drop the argument. A constant does not keep that fact: after constant scores = [3, 1, 2], the call scores::firstItem(defaultingTo 0) gets no warning.

Quick Fix: Remove the ‘defaultingTo’ Argument.

Taught on: Checked refinements › What a proof changes

redundant-key-check

Warning. An if guarded by hasKey looks the same key up again in its first statement. hasKey is a lookup itself, so the key is looked up twice.

[redundant-key-check]
Warning: This key is looked up twice
   ╭─┤ Ages.es:4:5 │
   │
 4 │     if ages::hasKey("kim") {
   │        ─────────┬─────────  
   │                 ╰─────────── asked here
 5 │        constant age = ages::value(at "kim", defaultingTo 0)
   │                       ──────────────────┬──────────────────  
   │                                         ╰──────────────────── and answered here
   │ 
   │ Help: Ask 'value(at:)' once and match its Optional, or use 'value(at:defaultingTo:)' or 'update(at:with:)'.
   │ 
   │ Note: 'hasKey' is a lookup of its own — it asks the Dictionary for the key's value and answers whether it found one.
───╯

Look the key up once and match the Optional: match ages::value(at "kim") -> {} { case #Value(age) { … } case #Empty {} }. Where a fallback is enough, value(at:defaultingTo:) needs no if.

ambiguous-nesting-level

Warning. An argument fits both the receiver’s type and the type it holds, so the call has two readings. On an Optional<Optional<Integer>>, nested::is(#Empty) asks whether nested itself is empty.

[ambiguous-nesting-level]
Warning: This Argument fits the receiver and what it holds
   ╭─┤ Nested.es:4:28 │
   │
 4 │     Terminal.print(nested::is(#Empty))
   │                            ─┐ ───┬──  
   │                             ╰────│──── this takes an Optional<Integer> as well
   │                                  │    
   │                                  ╰──── read as an Optional<Optional<Integer>> here
   │ 
   │ Help 1: Write '#Value(…)' around the Argument to ask whether the receiver holds it.
   │ Help 2: Name it in a Constant annotated 'Optional<Optional<Integer>>' to go on asking about the receiver.
   │ 
   │ Note: A call reaches the first entry its Arguments fit, and the entry taking the receiver's own Type is written first — so this asks whether the receiver IS the Argument, not whether it holds it.
───╯

Say which you mean. nested::is(#Value(#Empty)) asks whether it holds an empty Optional. To ask about the receiver, compare with a constant annotated at the outer level: constant outer: Optional<Optional<Integer>> = #Empty, then nested::is(outer).

Refactor: Wrap the Argument in ‘#Value(…)’. It is a refactoring rather than a Quick Fix, because both readings are valid.

Taught on: Optional › Nested Optionals

Choices

Declaring a choice and building its cases.

empty-choice

Error. A choice declares no cases.

[empty-choice]
Error: A Choice must declare at least one Case
   ╭─┤ Nothing.es:2:2 │
   │
 2 │     choice Nothing {}
   │     ────────┬────────  
   │             ╰────────── this Choice declares none
───╯

Declare at least one case.

Taught on: Choices and match › Building a case

unknown-case

Error. No case of that name exists where one was looked for. That place is a named choice, the matched value’s type, the choice the position expects, or, for a bare #Case nothing decides, every choice in scope.

Where the position decides a choice — an annotation, a return type, a parameter a direct argument is passed to, a match over a known subject — the report names that choice and lists the cases it declares. Every mode in the standard library is a bare case at a parameter, so this is how you discover what round(toward:) or trim(at:) will take:

[unknown-case]
Error: 'Colour' declares no Case '#Purple'
   ╭─┤ Colour.es:8:29 │
   │
 8 │     constant colour: Colour = #Purple
   │                                ───┬──  
   │                                   ╰──── no such Case
   │ 
   │ Note: This position takes a Colour: '#Red', '#Green', '#Blue'.
───╯

A case that carries a payload is listed with it — '#Value(item)' — so the note is a list you can write from, and a long list stops at eight with “and N more”. A case carries one value, so a payload of several members is listed as the record it is: '#Rect({ width, height })', which is what you write where the list stands. An overload whose candidates accept different choices gets one note each, and the message names none of them.

Where nothing decides the choice, the message is “No Choice in scope declares a Case ‘#Purple’”, a note names the choices that declare the nearest case name, and the Help says to annotate the value so that a choice has a say.

A match written on a value that holds the choice — a future answering one — is told so, and told to wait for it first. That is one report about the subject rather than one per arm: every case of such a match is refused, and each would otherwise say the same sentence about a different case name. Where the enclosing body cannot wait the Help names both steps, because complete is refused in a body that answers anything but a future:

[unknown-case]
Error: The matched value has no Case '#Red'
    ╭─┤ Name.es:15:10 │
    │
 15 │          case #Red { <- "red" }
    │                ─┬─  
    │                 ╰─── no such Case in this Union
    │ 
    │ Help: Declare the enclosing Function '-> Future<…>', which is what lets its body wait, then wait for it first — 'constant answered = complete …' — and match 'answered'.
    │ 
    │ Note: '#Red' is a Case of Colour, which is what a Future<Colour> holds.
────╯

Fix the case name.

Quick Fix: Change to ‘#Red’ when a case name is close. The near miss is drawn from the position’s own choice where there is one, so it is always a case that would resolve.

Taught on: Choices and match › Building a case

ambiguous-case

Error. A bare #Case is declared by more than one choice in scope. A bare #Value is a common cause, because Optional and Result both declare it.

[ambiguous-case]
Error: Case '#Red' is declared by more than one Choice
    ╭─┤ Colour.es:12:19 │
    │
 12 │     constant stop = #Red
    │                      ─┬─  
    │                       ╰─── 2 Choices in scope declare it
    │ 
    │ Help 1: Write 'Colour#Red' to pick 'Colour'.
    │ Help 2: Write 'Signal#Red' to pick 'Signal'.
    │ 
    │ Note 1: 'Colour' declares '#Red'.
    │ Note 2: 'Signal' declares '#Red'.
────╯

Prefix the case with its choice: Colour#Red. Where the expected type holds one generic choice applied twice, as Box<Integer> | Box<String>, one choice declares the case, so the report reads Case '#Full' fits more than one application of 'Box', and each help names the type arguments as well: Write 'Box<Integer>#Full' to pick 'Box<Integer>'. A match case writes no type arguments, so its helps name each choice once.

Quick Fix: Prefix with ‘Colour#’, one for each choice that declares the case. Where a generic choice is named without its type arguments, the prefix says which choice and leaves its type arguments to the position. A position that decides them, such as a declared type, settles them: Box#Full(1) under Box<Integer> | Crate compiles. Where nothing decides them, the prefix leaves undecided-type-arguments behind, by design.

Taught on: Choices and match › Building a case

missing-payload

Error. A case that carries a payload is written without one. A bare #Case is only for a case without a payload.

[missing-payload]
Error: Case '#Circle' requires a payload
   ╭─┤ Shape.es:7:26 │
   │
 7 │     constant shape: Shape = #Circle
   │                             ───┬───  
   │                                ╰───── no payload was given
   │ 
   │ Help: Write the payload, filling each member in: '#Circle({ radius = … })'.
   │ 
   │ Note: '#Circle' carries a { radius: Integer }.
───╯

Pass the payload, #Circle({ radius = 1 }), or #Circle(1) for a payload of one member. The Help spells the shape with the member names the note has just given the types of, and leaves the values as the … they are. A case whose default fills every member in gets a different Help — Its default fills every member in — write '#Circle({})'. — because a bare #Circle is a payload-free case’s spelling and stays one, however much of the payload is defaulted.

Taught on: Choices and match › Building a case

unexpected-payload

Error. A case without a payload is given one.

[unexpected-payload]
Error: Case '#Dot' does not carry a payload
   ╭─┤ Shape.es:7:31 │
   │
 7 │     constant shape: Shape = #Dot(1)
   │                                  ▲  
   │                                  ╰── nothing goes here
   │ 
   │ Help: Write '#Dot' on its own.
───╯

Write the case on its own: #Dot.

Quick Fix: Write ‘#Dot’ on its own.

Taught on: Choices and match › Building a case

payload-type-mismatch

Error. A payload does not fit the shape its case declares.

[payload-type-mismatch]
Error: This payload does not fit Case '#Circle'
   ╭─┤ Shape.es:7:34 │
   │
 7 │     constant shape: Shape = #Circle({ radius = "big" })
   │                                     ─────────┬────────  
   │                                              ╰────────── 'radius' is a { radius: String }, and '#Circle' declares an Integer
   │ 
   │ Note: '#Circle' carries a { radius: Integer }.
───╯

Write the payload the case declares: #Circle({ radius = 3 }).

The label reads 'radius' is a { radius: String } because of the one-member shorthand: a case of exactly one member takes that member’s value directly, so { radius = "big" } was read as the value OF radius and wrapped back up. The doubling in the label is that wrapping, not something you wrote.

A case of several members gets a second Help — The one-member shorthand '#Case(value)' only applies to single-member Cases. — because the shorthand is what a reader writing #Rectangle(2) reached for, and it is the one thing the member diff above cannot say. A single-member case gets no such Help: the shorthand would have accepted the value, so what is wrong is the value itself, which the note names the type of. Neither does a payload that writes the case’s record — a #Rectangle({ width = "wide", height = 2 }) names the members the case declares and got one value wrong, so nothing there reached for the shorthand.

A payload literal may name only the members its case declares, whether it writes them all or leaves some to the payload’s default. #Article({ slug = "choices", draft = true }) is this code, with the help Remove 'draft'. and the Quick Fix Remove ‘draft’. A record value passed as the payload, as in #Article(post), still carries what it holds.

Taught on: Choices and match › Building a case

unbindable-case-payload

Error. A case matcher binds one name, as in case #Rectangle(size), for a case whose payload has several members. One name binds a payload of exactly one member.

[unbindable-case-payload]
Error: 'Shape#Rectangle' has no single value to bind
   ╭─┤ Shape.es:9:20 │
   │
 9 │          case #Rectangle(size) {
   │                          ──┬─  
   │                            ╰─── this Case carries 2 values
   │ 
   │ Help: Take the payload apart instead: '#Rectangle({ width, height })'.
   │ 
   │ Note: Its values are 'width', 'height'.
───╯

Take the payload apart by its members, the way JavaScript destructures an object: case #Rectangle({ width, height }).

A binding written on a case that carries no payload reports the same code with its own message, label and Help — there is nothing to take apart, so the binding goes:

[unbindable-case-payload]
Error: 'Shape#Dot' has no single value to bind
    ╭─┤ Shape.es:12:13 │
    │
 12 │        case #Dot(size) { <- "dot" }
    │                  ──┬─  
    │                    ╰─── this Case carries no value
    │ 
    │ Help: Drop the binding — the Matcher alone is the test.
    │ 
    │ Note: A binding names the value a Case carries, and this one carries none.
────╯

Taught on: Patterns › In a case payload

case-default-not-a-literal

Error. A value in a payload default is computed, such as a function call. A payload default holds written values, or constants of the same module that hold them.

[case-default-not-a-literal]
Error: This value in a payload default is not a literal
   ╭─┤ Attempt.es:7:55 │
   │
 7 │        Get { url: String, retries: Integer } = { retries = standardRetries() },
   │                                                            ────────┬────────  
   │                                                                    ╰────────── this is worked out rather than written down
   │ 
   │ Help: Write a literal — a Number, a String, a Boolean, or a List, Record or Case value built out of those — or name a Constant of this Module whose value is one.
   │ 
   │ Note: A payload default is spliced into every construction of its Case, and a construction may stand in a Module that never named the Choice — so the value travels with the Case Type, and a name read where the Case is built would be a name that is not there.
───╯

Write the value, { retries = 3 }, or name a constant of this module: constant standardRetries = 3, then { retries = standardRetries }.

A default that names a constant rather than writing a record reports the same code with a message of its own, The default for Case '#Get' is not a Record Literal: which members a default fills in is read off the ones it writes, so the default itself is spelled out even where the values inside it are names. Its Help names the members the case carries — Write the members out — '= { url = …, retries = … }' names every member of '#Get', and a default may fill in any of them. — and leaves the values as the … they are.

The choice above is named Attempt rather than Request, which the standard library’s Http already declares: a program that reuses the name reports duplicate-type before it reaches this.

Taught on: Choices and match › Defaults for a payload

case-default-on-generic-choice

Error. A case of a generic choice has a payload default. Each use of the choice gives its own type arguments, so one default cannot fit them all.

[case-default-on-generic-choice]
Error: A generic Choice can not default a payload
   ╭─┤ Holder.es:3:41 │
   │
 3 │        Full { item: Item, count: Integer } = { count = 1 },
   │                                              ──────┬──────  
   │                                                    ╰──────── this default
   │ 
   │ Help: Write the member at each construction, or declare a Choice that takes no Type Parameters — one whose payload Types are written out, where a default has something to be checked against.
   │ 
   │ Note: 'Holder' abstracts over 1 Type Parameter, and a value written here can bind none of them — every use site decides them, and each would want a default of its own.
───╯

Write the member at each construction instead, or declare the choice without type parameters — choice Holder { Full { item: Integer, count: Integer } = { count = 1 }, Bare } — where the payload types are written out and a default has something to be checked against.

Taught on: Choices and match › Defaults for a payload

recursive-generic-choice

Error. A generic choice names itself in one of its payloads. Recursive type declarations are refused.

[recursive-generic-choice]
Error: A generic Choice can not name itself in a payload

Break the cycle. A List does not break it: a payload member typed List<Tree<Item>> reports this code too. To hold a tree, keep its nodes in a list and give each node the positions of its children in that list, or key the nodes in a dictionary.

Taught on: Generics › A choice applies its type arguments

indistinguishable-union-arms

Error. A payload union has two arms that mention a type parameter, such as Item | List<Item>. Two values of the choice are compared where the type arguments are still type parameters, so the arms cannot be told apart at runtime.

[indistinguishable-union-arms]
Error: This Choice's payload can not be compared here
   ╭─┤ Val.es:7:6 │
   │
 7 │        <- first::is(second)
   │           ────────┬────────  
   │                   ╰────────── two arms of a payload Union are one Type at runtime
   │ 
   │ Help: Compare the value where its Type Arguments are known, or write the arms so that something other than a Type Parameter tells them apart.
   │ 
   │ Note 1: 'Item | List<Item>' names 2 arms standing for a Type Parameter's values: 'Item', 'List<Item>'.
   │ Note 2: Type Parameters erase, so which arm a value belongs to is decided by the Type Arguments the receiver was applied to — and here they are Parameters themselves.
───╯

Compare where the type arguments are known, for example in a function that takes Val<Integer>. Or write the arms so that something other than a type parameter tells them apart.

undecided-type-arguments

Error. A case of a generic choice is built where no type arguments are written and none come from its position. A choice’s type arguments are written, never inferred from the payload.

[undecided-type-arguments]
Error: Nothing decides the Type Arguments of 'Holder#Bare'
   ╭─┤ Left.es:7:18 │
   │
 7 │     constant left = Holder#Bare
   │                     ─────┬─────  
   │                          ╰─────── no Type Arguments here, and nothing around it decides them
   │ 
   │ Help 1: Annotate the Declaration this is written into with 'Holder<…>', which is what decides them.
   │ Help 2: Or apply the Type Arguments here — 'Holder<…>#Bare', with the Type you mean in place of each '…'.
   │ 
   │ Note 1: 'Holder' takes 1 Type Parameter: 'Item'.
   │ Note 2: A Choice's Type Parameters are applied, never inferred — the payload is checked against them, it does not choose them.
───╯

Write the type arguments at the case, Holder<Integer>#Bare, or annotate the constant: constant empty: Holder<Integer> = Holder#Bare. The help to annotate stands only where a constant or a variable takes the case as its value, directly or as an arm of its define: an annotation anywhere else, such as around an argument, does not reach the case. The helps show the application with a blank per argument, and the notes name the choice’s own parameters — those names belong to the declaration and are in scope nowhere else, so writing one back is unknown-type.

Where a payload already decided some of the arguments, those are spelled and only the undecided ones are blank: a #Stopped({ value = "x" }) of a Progress<State, Result> reads Progress<…, String>. The parentheses stay on wherever the case carries a payload, so the spelling in the help is one that compiles.

Taught on: Generics › A choice applies its type arguments

Match

Taking a value apart with match.

missing-case

Error. A match does not handle every member of the matched type. The Note lists what is not handled.

[missing-case]
Error: This Match Expression does not handle every Case
   ╭─┤ Colour.es:9:6 │
   │
 9 │        <- match colour -> String {
   │                 ───┬──  
   │                    ╰──── this is a Colour
   │ 
   │ Help: Add 'case Colour#Blue', or a 'case _' that covers the rest.
   │ 
   │ Note: Unhandled: 'Colour#Blue'.
───╯

Add a case for each, or a case _ for the rest.

A case of a generic choice is named without type arguments, as case Box#Full, which matches it in every application. On a Box<Integer> | Box<String> that already has case Box<Integer>, the Help names case Box<String> instead, where the file has a name for Box: case Box<Integer> also takes a Box<String>#Empty, and a case for that application reports it as type-argument-overlap.

Quick Fix: Add missing Cases writes an empty case for each, with a case _ for any member that cannot be written as a matcher.

Taught on: Choices and match › Guards, order and exhaustiveness

unreachable-case

Warning. A case can never run, because an earlier case already matches all of its values.

[unreachable-case]
Warning: This Case can never match
    ╭─┤ Colour.es:15:9 │
    │
  9 │          case #Red {
    │               ──┬─  
    │                 ╰─── this Case runs first
    │ 
 15 │          case #Red {
    │               ──┬─  
    │                 ╰─── an earlier Case already answers for every Type this one matches
    │ 
    │ Help: Remove this Case — the Case above answers for every value it would take, in whichever order the two are written.
    │ 
    │ Note: Cases are tried in order, and the first one that fits wins.
────╯

Delete the second case #Red, since the first one already handles #Red. Two matchers that ask the same question swallow each other in whichever order they are written, so reordering is not offered for them. Where the covered case is narrower, the Help is Remove this Case, or write it above the one that covers it.

Several cases can cover one together: a case _ after case #Red and case #Green of a choice Light { Red, Green } is reached by no value. Every case that claims a member is labelled, and the Help is Remove this Case — the Cases above answer for every value it would take. Moving it above them would swallow them instead.

A case that overlaps no member at all reports under the same code, with its own Help:

[unreachable-case]
Warning: This Case can never match
    ╭─┤ Describe.es:5:9 │
    │
  4 │        constant described = match value -> String {
    │                                   ──┬──  
    │                                     ╰──── this is an Integer | Boolean
    │ 
  5 │          case String { <- "never" }
    │               ───┬──  
    │                  ╰──── String is not a member of the matched Union
    │ 
    │ Help: Remove this Case, or name a member of Integer | Boolean.
────╯

Removal is always safe for that one: a case the exhaustiveness check never counted cannot be the case holding exhaustiveness up.

Quick Fix: Remove unreachable Case.

Taught on: Choices and match › Guards, order and exhaustiveness

erased-case-conflict

Error. An earlier case covers this one because types erase before a match runs. A generic case Value accepts every value that reaches it, so no case below it can run.

[erased-case-conflict]
Error: This Case can never match
   ╭─┤ Describe.es:7:9 │
   │
 4 │          case Value {
   │               ──┬──  
   │                 ╰──── this Case runs first
   │ 
 7 │          case String {
   │               ───┬──  
   │                  ╰──── an earlier Case already answers for every Type this one matches
   │ 
   │ Help: Write this Case above 'case Value', which can only ever be the last one.
   │ 
   │ Note 1: Cases are tried in order, and the first one that fits wins.
   │ Note 2: Types erase before a Match runs, so the Generic Case 'Value' narrows nothing and accepts every value that reaches it.
───╯

Write the generic case last.

A record matcher whose member names a type parameter, such as case { a: Item }, is reported the same way. It still checks that a is present, but not what type a holds, so the Help asks for the later case to be written above it: Write this Case above 'case { a: Item }', which takes 'a' whatever Type it holds.

Two record types that differ only in a function member’s signature report the same code with a different Help, because reordering cannot help there:

[erased-case-conflict]
Error: This Case can never match
    ╭─┤ Show.es:8:9 │
    │
  7 │          case Handler { <- "a handler" }
    │               ───┬───  
    │                  ╰───── this Case runs first
    │ 
  8 │          case Logger { <- "a logger" }
    │               ───┬──  
    │                  ╰──── an earlier Case already answers for every Type this one matches
    │ 
    │ Help: Tell the two Cases apart by a member that survives to runtime — a member whose Type is not a Function.
    │ 
    │ Note 1: Cases are tried in order, and the first one that fits wins.
    │ Note 2: A Function's Signature erases before a Match runs, so a Function-typed member is only ever checked for being callable — which makes these two Matchers ask the same question.
────╯

No guard helps, in either position: on the later case it changes nothing, because the earlier one decides first and never reaches it; on the earlier case it takes that case’s claim away and leaves no case making it, which is missing-case — and both of that report’s answers are swallowed by the case that decides first. Two matchers asking one erased question admit no exhaustive match at all, so the only edit is to make them ask two.

The same conflict is reported about a method call’s dispatch branches, where the namespaces stand in for the cases and the receiver is underlined instead:

[erased-case-conflict]
Error: The branch for Logger can never run
    ╭─┤ Show.es:19:13 │
    │
 19 │        <- value::describe()
    │           ──┬──  ────┬───  
    │             ╰────────│───── this is a Handler | Logger
    │                      │     
    │                      ╰───── Handler answers for every value it would take
    │ 
    │ Help: Tell the two member Types apart by something that survives to runtime — a member whose Type is not a Function.
    │ 
    │ Note 1: A branch is picked by the receiver's Type at runtime, and the first one that fits wins.
    │ Note 2: A Function's Signature does not survive to be checked — a member Type naming a callback is only ever asked whether the value is callable, which makes two of them ask the same question.
────╯

A refinement’s predicate erases too, so on { a: Small } | { a: Large }, with Small and Large refinements of Integer, the branch for Large never runs. Where a refinement tells apart only some of the values, the branch never sees those. The help asks for a value of one member type, whose own namespace answers without a runtime check.

Two applications of one case ask one erased question too. With b: Box<Integer> | Box<String>, b::is(#Empty) has a branch for each, and Box<Integer>#Empty and Box<String>#Empty differ only in their type arguments. The note says so, and the help names the edit that removes the overlap: Write the receiver's Type as one application of 'Box'.

Taught on: Generics › Types erase before a match

empty-list-overlap

Warning. An earlier case also matches this one’s empty lists. Item types erase before a match runs, so an empty list fits every list type.

[empty-list-overlap]
Warning: This Case never sees an empty List
   ╭─┤ Describe.es:7:9 │
   │
 4 │          case List<String> {
   │               ──────┬─────  
   │                     ╰─────── this Case runs first
   │ 
 7 │          case List<Integer> {
   │               ──────┬──────  
   │                     ╰──────── an empty List<Integer> fits the Case above too
   │ 
   │ Help: Guard the Cases with 'where @::hasItems()' and answer for the empty List in a Case of its own.
   │ 
   │ Note 1: Cases are tried in order, and the first one that fits wins.
   │ Note 2: Item Types erase before a Match runs, so a List Matcher asks about the items the value holds — and an empty List holds none, which makes it a value of every List Type there is.
───╯

Guard the cases with where @::hasItems(), and handle the empty list in a case of its own, such as a final case _.

The same warning is reported about a method call’s dispatch branches, where there is no match to guard yet. Its Help spells the whole shape — the guards, the case of its own, and the call moved inside each arm — because a match written without the guards is picked by the same erased question the branches were, and reports this again in the match’s own wording.

Quick Fix: Guard the Cases with ‘where @::hasItems()’ and add a ‘case _’ guards every case that names a list and writes the arm those guards make necessary. It writes both halves because either alone is worse than neither: guarding one case moves the warning one case down, and guarding them all without the arm turns a warning into a missing-case error. Where the match already ends in case _, only the guards are written, and the title says so.

Taught on: Generics › Types erase before a match

empty-dictionary-overlap

Warning. An earlier case also matches this one’s empty dictionaries. Key and value types erase before a match runs, so an empty dictionary fits every dictionary type.

[empty-dictionary-overlap]
Warning: This Case never sees an empty Dictionary
   ╭─┤ Describe.es:7:9 │
   │
 4 │          case Dictionary<String, Integer> {
   │               ─────────────┬─────────────  
   │                            ╰─────────────── this Case runs first
   │ 
 7 │          case Dictionary<Integer, String> {
   │               ─────────────┬─────────────  
   │                            ╰─────────────── an empty Dictionary<Integer, String> fits the Case above too
   │ 
   │ Help: Guard the Cases with 'where @::hasEntries()' and answer for the empty Dictionary in a Case of its own.
   │ 
   │ Note 1: Cases are tried in order, and the first one that fits wins.
   │ Note 2: Key and value Types erase before a Match runs, so a Dictionary Matcher asks about the entries the value holds — and an empty Dictionary holds none, which makes it a value of every Dictionary Type there is.
───╯

Guard both cases, as in case Dictionary<String, Integer> where @::hasEntries() { … }, and handle the empty dictionary in a final case _ { … }. A method call’s dispatch branches report it too, with the shape empty-list-overlap spells, asking the dictionary’s own question.

Quick Fix: Guard the Cases with ‘where @::hasEntries()’ and add a ‘case _’.

Quick Fix: Guard it with ‘where @::hasEntries()’, on the case that runs first.

Taught on: Generics › Types erase before a match

type-argument-overlap

Warning. An earlier case for another application of a generic choice also matches some of this one’s values. Type arguments erase before a match runs, so a case is told from the same case of another application by its payload alone. A case with no payload fits every application, and so does a payload with nothing in it to tell them apart, such as an empty list.

[type-argument-overlap]
Warning: This Case never sees Parcel<String>#Empty
    ╭─┤ Match.es:70:8 │
    │
 69 │        case Parcel<Integer> { <- "numbers" }
    │             ───────┬───────  
    │                    ╰───────── this Case runs first
 70 │        case Parcel<String>  { <- "words" }
    │             ───────┬──────  
    │                    ╰──────── Parcel<String>#Empty fits the Case above too
    │ 
    │ Help: Write 'case Parcel#Empty' above the Case that runs first, so one Case answers for it in every application.
    │ 
    │ Note 1: Cases are tried in order, and the first one that fits wins.
    │ Note 2: Type Arguments do not survive to runtime, so Parcel<String>#Empty is told from Parcel<Integer>#Empty by its payload alone, and its payload holds nothing that tells them apart.
────╯

Write the case the Help names above the case that runs first. A case matcher such as case Parcel#Empty takes its case in every application, so it answers for all of them. The cases for each application then see only the values their payloads tell apart. The Help names every case the earlier one takes.

The case can cross inside a member too. With choice Holder { Hold { box: Box<Integer> | Box<String> } }, case #Hold({ box: Box<Integer> }) above case #Hold({ box: Box<String> }) takes every Hold whose box is Box<String>#Empty. No pattern can name a case of every application, so the Help binds the member in one case and matches it there: case Holder#Hold({ box }), whose match box starts with case Box#Empty. A record matcher such as case { box: Box<Integer> } gets the same Help, with case { box }. A member further down a path of records is bound through as, as in case Holder#Hold({ wrap as { box } }). A list that holds only such cases crosses with them, so case List<Box<Integer>> above case List<Box<String>> takes every [Box<String>#Empty]. No case can be written for that list, and a where @::hasItems() guard leaves it crossing, so the Help asks for one application of Box in the matched value’s type.

A method call’s dispatch branches over two applications report it too, where a payload such as an empty list holds nothing to tell them apart. There is no match to add a case to yet, so the Help asks for one: the case of its own first, then a case for each application that calls the method. Where the case crosses inside a member, as on a { box: Box<Integer> } | { box: Box<String> } receiver, no case can be written for it, and the Help asks for the receiver’s type as one application of Box. A branch that takes every value of another is erased-case-conflict instead.

Taught on: Generics › Types erase before a match

dispatch-overlap

Warning. Two branches of a method call on a union receiver have member types that share values, so a value of both runs the branch the compiler orders first. The values really are shared: { a = "x" } is a Left and a Right at once. Where a refinement in the earlier branch would turn the value away, as { a: Small } turns away a { a: Large }, the check sees only two integers, and the call is erased-case-conflict instead. A refinement both branches share turns nothing away, so it is no erasure, and neither does Integer where @::isLessThan(5) against isLessThan(10), since the compiler compares two refinements of an integer written as ranges, inclusive ones and isNot among them. Where no range decides, the warning says only what is known. A case cannot test a member type that holds a refinement, so there the help asks for a value of one member type instead of a match.

[dispatch-overlap]
Warning: The branch for Right never sees the values Left shares with it
    ╭─┤ Sides.es:18:13 │
    │
 18 │        <- value::describe()
    │           ──┬──  ────┬───  
    │             ╰────────│───── this is a Left | Right
    │                      │     
    │                      ╰───── a value of both takes the branch for Left, which is tried first
    │ 
    │ Help: Match the receiver with a Case for each member Type, in the order their shared values should go, and call the Method inside each.
    │ 
    │ Note 1: A branch is picked by the receiver's Type at runtime, and the first one that fits wins.
    │ Note 2: A value can be a Left and a Right at once, and fits both branches.
────╯

The order of the branches is the compiler’s, not yours. A match tries its cases in the order they are written, so match the receiver, with a case for each member type in the order its shared values should go, and call the method inside each: case Right { <- @::describe() } above case Left { <- @::describe() } sends { a = "x" } to Rights. Overlaps that erasure causes have codes of their own: empty-list-overlap, empty-dictionary-overlap and type-argument-overlap.

Taught on: Namespaces and methods › Choosing between namespaces

refinement-as-matcher

Error. A case tests for a checked refinement, such as case NonZeroInteger. The predicate erases before the program runs, so the case could only test the base type.

[refinement-as-matcher]
Error: A Matcher can not test for 'NonZeroInteger'
   ╭─┤ Describe.es:4:9 │
   │
 4 │          case NonZeroInteger {
   │               ───────┬──────  
   │                      ╰──────── this is a checked refinement
   │ 
   │ Help: Match on 'Integer' and prove the predicate inside the arm, the way every 'NonZeroInteger' is proven: an 'if' condition, a Case naming a written value, or a written value.
   │ 
   │ Note: A refinement's predicate erases before the Program runs, so the emitted check could only ask about 'Integer' — and the arm would run for values the predicate refuses.
───╯

Match the base type and prove the predicate inside the arm: case Integer { if @::isNot(0) { … } else { … } }.

Taught on: Checked refinements › A match proves its cases

match-on-non-union

Error. A match is written on a value that is not a union or a choice. Boolean is neither: unlike TypeScript’s boolean, it is not the union true | false, so case true is refused too. An Integer or a String can be matched by value instead, under the rules of literal-match-shape.

[match-on-non-union]
Error: Match Expressions require a Union Type
   ╭─┤ Ready.es:4:25 │
   │
 4 │     constant label = match ready -> String {
   │                            ──┬──  
   │                              ╰──── this is a Boolean
   │ 
   │ Help: Ask about the value with an 'if', or choose between answers with a 'define'.
   │ 
   │ Note: Matching a Type with only one possible shape has only one outcome.
───╯

Use if or define for a Boolean.

Taught on: Choices and match › Matching something other than a choice

literal-match-shape

Error. A match on an Integer or a String breaks a rule of matching by value. Most often it names values and has no last case for the values it did not name. The label points at the case that breaks the rule.

[literal-match-shape]
Error: This Match has no Case for the rest of the values
   ╭─┤ Describe.es:3:6 │
   │
 3 │        <- match count -> String {
   │                 ──┬──  
   │                   ╰──── this is an Integer
   │ 
 7 │          case 1 {
   │               ▲  
   │               ╰── this Case names a value, not the rest of them
   │ 
   │ Help: Add a 'case _' below, for every value the Cases above miss.
   │ 
   │ Note 1: A Match on an Integer takes the VALUE apart: every Case names a value, and the last one answers for every value the Cases above it did not name.
   │ Note 2: There are more values of Integer than a Match can write down, so the last Case is what makes it answer for all of them.
───╯

End the match with case _: case 0 { … } case 1 { … } case _ { … }.

The other three shapes carry their own Helps, each built from what this match is:

  • A case that names no value. Where the match already ends in a case for the rest, the Help asks for the value or for a removal — moving this case below the last one only makes that one the case naming no value, which is this report one case further down. Where the match has no end yet, the Help offers the move.
  • A case that names a value of another type. Name an Integer, or remove this Case. A case compared across types is never true, so removing it changes nothing about what the match answers.
  • A case that names a value and still carries a guard. Take the Guard off, and ask its question inside the Handler with an 'if'.

Quick Fix: Add a ‘case _’ for the rest of the values. A guard on a case that names a value gets Drop the Guard.

Taught on: Choices and match › Matching something other than a choice

Define

Choosing a value with define.

define-without-otherwise

Error. Every arm of a define has a condition, so nothing is returned when they all fail.

[define-without-otherwise]
Error: This 'define' has no 'otherwise' arm
   ╭─┤ Label.es:4:19 │
   │
 4 │ ╭─▶     constant label = define {
 5 │ │          as "go" if ready
 6 │ ├─▶     }
   │ │           
   │ ╰─────────── every value here has a condition on it
   │ 
   │ Help: Write the last arm as 'as <value> otherwise'.
   │ 
   │ Note: A 'define' answers with a value wherever it stands, so one of its arms has to be the one that always holds.
───╯

End it with an otherwise arm: as "wait" otherwise.

Quick Fix: Add an ‘otherwise’ arm to fill in — it writes as {} otherwise, which parses and is visibly not an answer. Wherever the define has a type to answer, the hole is reported as an arm that answers {}; the title says the value is still yours to write.

Taught on: Conditions › otherwise is mandatory

unreachable-define-arm

Error. An arm is written below the otherwise arm. The otherwise arm always holds, so nothing below it runs.

[unreachable-define-arm]
Error: This arm stands below the 'otherwise' arm
   ╭─┤ Label.es:7:3 │
   │
 7 │        as "stop" if ready::negate()
   │        ──────────────┬─────────────  
   │                      ╰─────────────── nothing here can ever be reached
   │ 
   │ Help: Move this arm above the 'otherwise' arm, or delete it.
   │ 
   │ Note: The 'otherwise' arm is the one that always holds, so a 'define' answers there whenever it gets that far.
───╯

Move as "stop" if ready::negate() above as "wait" otherwise, or delete it.

Quick Fix: Remove the arm or Move the arm above the ‘otherwise’ arm.

Taught on: Conditions › Arms are tried in order

define-without-answer-type

Error. The compiler cannot tell what type a define returns. Here each arm is a case of a generic choice, and no arm gives its type arguments.

[define-without-answer-type]
Error: Nothing decides what this 'define' answers
   ╭─┤ Fetched.es:4:21 │
   │
 4 │ ╭─▶     constant fetched = define {
 5 │ │          as #Empty    if skipped
   │ │             ───┬──  
   │ │                ╰──── this arm has none of its own to lend it
 6 │ │          as #Value(1) otherwise
 7 │ ├─▶     }
   │ │           
   │ ╰─────────── this 'define' has no answer Type
   │ 
   │ Help 1: Write the answer Type on the 'define' itself: 'define -> Type { … }' — it is pushed into every arm.
   │ Help 2: Or annotate the Declaration it stands in, where it stands in one. An Argument position hands nothing down: a call picks its Overload BY the Arguments, so no Parameter Type is decided before they are read.
   │ 
   │ Note: A 'define' takes its answer Type from its arrow, from the position it stands in, or from what its arms answer with — and an arm that decides no Type Arguments of its own leaves nothing to take.
───╯

Write the type on the define, define -> Optional<Integer> { … }, or annotate the constant: constant fetched: Optional<Integer> = define { … }. A define passed directly as an argument needs the arrow, because an argument position passes no type down.

This program reports three times, not once: each arm is also asked what decides its own type arguments, and the bare #Value is also a case two choices in scope declare. The report above comes first — it is written highest in the file — and its helps are the ones that answer all three. The other two are undecided-type-arguments and ambiguous-case, and writing the answer type on the define clears them with it.

Taught on: Conditions › What a define returns

define-without-cases

Warning. A define has only its otherwise arm, so it has nothing to choose between.

[define-without-cases]
Warning: This 'define' has no cases
   ╭─┤ Label.es:2:19 │
   │
 2 │ ╭─▶     constant label = define {
 3 │ │          as "wait" otherwise
 4 │ ├─▶     }
   │ │           
   │ ╰─────────── nothing here is decided by cases
   │ 
   │ Help: Write the 'otherwise' value on its own, or add the arms this 'define' was going to ask.
   │ 
   │ Note: A 'define' answers with the value of the first arm whose Condition holds — and the 'otherwise' arm is the one that holds when none of them did.
───╯

Write the value on its own, or add the arms.

Quick Fix: Write the value on its own.

Taught on: Conditions › otherwise is mandatory

Patterns

Naming the parts of a value.

refutable-pattern

Error. A pattern in a declaration or a parameter constrains a member by value, such as { width = 0, height }. A declaration has nowhere to go when the value does not match.

[refutable-pattern]
Error: A Declaration can not match a value against a Pattern
   ╭─┤ Rectangle.es:3:13 │
   │
 3 │     constant { width = 0, height } = rectangle
   │                ────┬────  
   │                    ╰────── this can decline the value
   │ 
   │ Help: Write only 'width' to bind it, and ask about its value with 'match'.
   │ 
   │ Note: A Matcher may constrain a member by value, because an arm that declines falls through to the next one. A Declaration has nowhere to fall through to.
───╯

Bind the member, constant { width, height } = rectangle, and ask about its value with match.

Taught on: Patterns › Patterns that cannot decline

redundant-pattern-binder

Error. A matcher’s own pattern ends in as name, as in case { x, y } as whole. Inside the arm, @ already names the matched value.

[redundant-pattern-binder]
Error: A Matcher's Pattern can not name the whole value
   ╭─┤ Point.es:5:17 │
   │
 5 │        case { x, y } as whole {
   │                      ────┬───  
   │                          ╰───── '@' already names it
   │ 
   │ Help: Drop the 'as whole' and write '@' where 'whole' was meant.
   │ 
   │ Note: Inside an arm, '@' is the scrutinee narrowed to what the Matcher established — which is exactly what this would name a second time.
───╯

Write @ where the name was used: case { x, y } { <- @.x::add(y) }. A case payload pattern may still carry as: case #Rectangle({ width, height } as box) compiles.

Quick Fix: Use ‘@’ instead of ‘whole’.

Taught on: Patterns › In a match arm

pattern-without-body

Error. A pattern is written in a protocol requirement’s signature. A requirement has no body to bind the names in.

[pattern-without-body]
Error: A Protocol requirement can not take a Parameter apart
   ╭─┤ Measurable.es:3:11 │
   │
 3 │        area(of { width, height }: { width: Integer, height: Integer }) -> Integer
   │                ────────┬────────  
   │                        ╰────────── no body to bind these in
   │ 
   │ Help: Write one name, and take it apart where it is used.
   │ 
   │ Note: A Protocol requirement declares what a call looks like and nothing about how it is carried out, so a Pattern here would name parts for nobody to read.
───╯

Write one parameter name in the signature, and take it apart in the method that fulfils it. A provided method, one with a body, may take a parameter apart as any method does.

Taught on: Protocols › What a requirement can be

Inference

What the compiler could not work out on its own.

uninferable-type-parameter

Error. The compiler cannot infer a function’s type parameter at a call, because no argument gives it the type. A function with no parameters, such as empty<infer Item>() -> List<Item>, reports it when called as empty().

[uninferable-type-parameter]
Error: Type Parameter 'Item' could not be inferred
   ╭─┤ Empty.es:6:19 │
   │
 6 │     constant items = empty()
   │                      ───┬───  
   │                         ╰───── nothing here determines what it binds to
   │ 
   │ Help 1: Give the Type Parameter a place among the Parameters, so that an Argument binds it.
   │ Help 2: Or write the value itself, with the Type it answers written out — 'constant value: List<…> = []', with the Type you mean in place of each '…'.
───╯

The two helps are the only ways out, because no syntax pins a type argument at a call: empty<Integer>() is foreign-syntax. Annotating the constant does not help either. Give the function a parameter whose type mentions the type parameter, so that the compiler infers it from the argument: emptyLike<infer Item>(_ sample: List<Item>). Or write the value the call would have returned, with its type spelled out: the second help is spelled from what the call returns, [] for a list, [=] for a dictionary and #Empty for an optional, and it is left out where the type has no empty value to write.

A call that passes a function literal with no -> Type gets a different help, because neither of those two is the reader’s to make: the type parameter already has its place among the parameters — loop’s Answer is written in the step’s own answer type — and the signature it has that place in belongs to the standard library.

[uninferable-type-parameter]
Error: Type Parameter 'Answer' could not be inferred
   ╭─┤ Never.es:2:19 │
   │
 2 │ ╭─▶     constant never = loop(startingWith 0,
 3 │ ├─▶        step (state) { <- #Continue(state::add(1)) })
   │ │                                                          
   │ ╰────────────────────────────────────────────────────────── nothing here determines what it binds to
   │ 
   │ Help: Write the Function literal's return Type — '-> Type' after its Parameter list — which is what binds 'Answer'.
───╯

Write it: step (state) -> Step<Integer, Integer> { <- #Continue(state::add(1)) }.

Taught on: Generics › Only the arguments bind

uninferable-parameter-type

Error. A function literal’s parameter has no type, and the literal is not passed as an argument. Only a literal written directly as an argument takes its types from the call.

[uninferable-parameter-type]
Error: The Type of Parameter 'number' could not be inferred
   ╭─┤ Double.es:2:21 │
   │
 2 │     constant double = (number) {
   │                        ───┬──  
   │                           ╰──── this Parameter has no Type
   │ 
   │ Help: Write the Parameter's Type and the Function's return Type — a literal outside Argument position takes neither from around it.
   │ 
   │ Note: Only a Function passed as an Argument takes its Types from the surrounding context.
───╯

Write the type: (_ number: Integer) -> Integer { … }. Both halves are named in one report, because a literal written outside argument position is missing both — writing only the parameter’s type reaches missing-return-type on the next run.

Taught on: Functions as values › Literals written as arguments

path-without-context

Error. A member path such as .price is written where no function of one parameter is expected, so there is no type to read the member from.

[path-without-context]
Error: A member path stands where no Function is expected
   ╭─┤ Price.es:2:19 │
   │
 2 │     constant price = .price
   │                      ───┬──  
   │                         ╰──── this path names no value
   │ 
   │ Help 1: Pass the path where a Function of one Parameter is expected — '::map(.price)'.
   │ Help 2: Or write the Function literal, with the Parameter and return Types a path leaves out — '(_ item: <Type>) -> <Type> { <- item.price }', filling each '<Type>' in.
   │ 
   │ Note 1: A member path is a Function the Compiler writes for you, so it needs a Parameter Type to read the members off — and only a position expecting a Function of one Parameter names one.
   │ Note 2: This position expects no particular Type.
───╯

Pass the path where a function is expected, as in products::map(.price), or write a function literal. Outside argument position a literal takes no types from around it, so it has to write both of its own: (_ item: Product) -> Integer { <- item.price }. The help writes each of them as <Type> rather than naming one — a type is exactly what this position does not name, which is why the path was refused. Where the position names a type that is not a function at all the help changes — nothing a function literal can say fits an Integer, so it offers the member read instead, and the ::map clause goes with it.

The same code refuses a path passed where a function of one parameter is expected, but whose parameter the call leaves undecided. In free(5, .price) against free<infer T>(_ items: List<T>, _ by: (_ item: T) -> Integer), the 5 binds no T, so no type says what price is. The help writes the function literal, whose parameter type then decides T.

Taught on: Functions as values › Member paths

uninferable-item-type

Error. A function literal captures a variable declared as [] before an assignment gives it an item type.

[uninferable-item-type]
Error: 'items' is captured before its item Type is decided
   ╭─┤ Items.es:5:6 │
   │
 2 │     variable items = []
   │              ──┬──  
   │                ╰──── declared with nothing to say what it holds
   │ 
 5 │        <- items::length()
   │           ──┬──  
   │             ╰──── captured here as a List<Unknown>
   │ 
   │ Help: Annotate the declaration — 'variable items: List<Integer>', for instance — so the Function is checked against the Type it will hold.
   │ 
   │ Note: An empty List Literal leaves its item Type unknown until an assignment decides it, and this Function was checked before that happened.
───╯

Annotate the variable: variable items: List<Integer> = []. The help spells that annotation from the declaration you wrote — its keyword, and its type with the blank filled in at the depth the blank sits — so a constant f = Async.deferred(() { <- [] }) is told to write constant f: Future<List<Integer>>. The item type itself is an example and says so: nothing was refused here, so there is no written value to read the blank off.

uninferable-return-type

Error. A function literal’s return type cannot be worked out from its body. A body that forgets <- is the usual cause: (n) { n::add(1) } returns nothing.

[uninferable-return-type]
Error: The return Type could not be inferred from the body
   ╭─┤ Double.es:2:34 │
   │
 2 │     constant doubled = [1, 2]::map((number) {
   │                                     ───┬──  
   │                                        ╰──── the body's Type is not determined here
   │ 
   │ Help 1: Return the value with '<-' — a body whose last line is a value answers with nothing.
   │ Help 2: Or, where the body is meant to answer nothing, write '-> {}' after its Parameter list.
───╯

Return the value, (number) { <- number::multiply(with 2) }. Where the body is meant to answer nothing, write -> {} instead; any other return type leaves it short of a <-, which missing-return then reports. Both helps are offered only where the body’s last line is a value; a body that does return and still answers nothing is asked for its -> Type and nothing else.

Taught on: Coming from JavaScript › Functions

uninferable-property-type

Error. A static property without a type annotation is read where its value cannot be typed yet: in code checked before what the value reads is declared, or from another module of its import cycle.

[uninferable-property-type]
Error: 'Square.side' is read before its Type is decided
   ╭─┤ Square.es:9:10 │
   │
 3 │        <- Square.side::multiply(with 4)
   │                  ──┬─  
   │                    ╰─── read where its value can not be typed
   │ 
 9 │        static side = width
   │               ──┬─  
   │                 ╰─── no annotation, so its value decides its Type
   │ 
   │ Help 1: Annotate 'Square.side' with its Type: 'static side: Type = …'.
   │ Help 2: Or declare what its value reads above every read of it.
   │ 
   │ Note: A static Property without an annotation takes its value's Type, so it can be read only where its value can be typed.
───╯

A namespace is hoisted, so a function above it may call its methods. A static property without an annotation has its value’s type, though, and width does not exist yet where perimeter is checked. Annotate the property, static side: Integer = width, or declare width above perimeter. Either way the program prints 12. The report stands on the property and labels every read, so one annotation answers them all. The second help is offered only where every read came before a name the value uses; where the value’s type has an undecided part, as a [] that a later assignment fills, only the annotation is offered.

A read that runs before the namespace exists is use-before-declaration instead, and a value with a mistake of its own reports that mistake alone. A module of an import cycle never reads such a property typed, whichever module the compile starts from, since the other module may be checked first. Its report stands on its first read, without a label on the property, and offers only the annotation.

Taught on: Namespaces and methods › Where a namespace can be used

missing-return-type

Error. A function literal that is not passed as an argument has no -> Type.

[missing-return-type]
Error: This Function must write its return Type
   ╭─┤ Double.es:2:20 │
   │
 2 │     constant double = (_ number: Integer) {
   │                       ─────────┬─────────  
   │                                ╰─────────── no '-> Type' here
   │ 
   │ Note: Only a Function passed as an Argument takes its Types from the surrounding context.
───╯

Write the return type: (_ number: Integer) -> Integer { … }.

Taught on: Functions as values › Function literals

Protocols

Protocols, bounds and conformances.

protocol-as-value

Error. A protocol name is used as a value. A protocol appears only in a bound, <infer T is Comparable>, or in a conformance clause, is Comparable.

[protocol-as-value]
Error: Protocol 'Comparable' can not be used as a value
   ╭─┤ Compare.es:2:22 │
   │
 2 │     constant ordering = Comparable
   │                         ─────┬────  
   │                              ╰────── this names a Protocol
   │ 
   │ Note: A Protocol is only usable as a Generic bound ('<infer T is Comparable>') or in a conformance clause ('is Comparable').
───╯

Use the protocol in a bound or a conformance clause.

Taught on: Protocols › What a protocol is not

namespace-as-value

Error. A namespace is used as a value, as in Terminal.inspect(Clock). It holds methods and statics, and no namespace is a value, whether the standard library, your program or an import declares it.

[namespace-as-value]
Error: Namespace 'Clock' can not be used as a value
   ╭─┤ Clock.es:8:19 │
   │
 8 │     Terminal.inspect(Clock)
   │                      ──┬──  
   │                        ╰──── this names a Namespace
   │ 
   │ Help: Read a member off it, as in 'Clock.now'.
   │ 
   │ Note: A Namespace holds Methods and statics, and is no value of its own.
───╯

Read a member off the namespace, as in Clock.now or Clock.now(), or pass a value in its place. The help names a member that reads as a value where the namespace has one: a static property first, then a method with one signature and no protocol bound, a static method before the others.

Taught on: Namespaces and methods › Statics and the dot

protocol-as-type

Error. A protocol name is used as a type, for example in an annotation. Unlike a TypeScript interface, a protocol is not a type.

[protocol-as-type]
Error: Protocol 'Comparable' can not be used as a Type
   ╭─┤ Compare.es:2:18 │
   │
 2 │     constant count: Comparable = 1
   │                     ─────┬────  
   │                          ╰────── this names a Protocol
   │ 
   │ Note: A Protocol is only usable as a Generic bound ('<infer T is Comparable>') or in a conformance clause ('is Comparable').
───╯

Use a concrete type, or a type parameter bounded by the protocol: <infer T is Comparable>.

Taught on: Protocols › What a protocol is not

unsatisfied-bound

Error. A type argument does not conform to the protocol its type parameter is bound to.

[unsatisfied-bound]
Error: { x: Integer } does not conform to 'Comparable'
   ╭─┤ Largest.es:6:17 │
   │
 6 │     Terminal.print(largest(of [{ x = 1 }, { x = 2 }]))
   │                    ─────────────────┬────────────────  
   │                                     ╰────────────────── this binds a Type Parameter bound to 'Comparable'
   │ 
   │ Help: Declare a Namespace 'for { x: Integer } is Comparable'.
   │ 
   │ Note: No Namespace in scope makes { x: Integer } conform to 'Comparable'.
───╯

Pass a type that conforms, or declare a namespace that makes this type conform, as the Help shows.

The Help is written for whatever the type turns out to be, and eight shapes read differently:

  • A bare case. Annotate the value at 'Colour': a bare Case binds the Case, not the Choice. — namespace X for Colour#Red is … is not a spelling, so what moves is the value’s annotation. That is the whole edit where the choice itself conforms. Where it does not, annotating only moves the refusal one type wider, so the choice’s own Help is given in its place: declaring namespace Doors for Door is Printable {} makes a member written Door#Open print, with no annotation at all. A choice the file has no name for is judged the same way, and either Help leads with its import.
  • A choice another module declares. 'Problem' is declared in Parser.es — import it here, so its derived 'Equatable' is in scope. A choice derives equality wherever it is in scope, so the edit is an import rather than a second conformance. A Quick Fix writes the entry.
  • A namespace the file has not imported. 'IntegerSized' in ./Sized.es makes Integer conform to 'Sized' — import it. A module the file already imports from exports a namespace that makes the type conform, so the edit is an import of it. A Quick Fix writes the entry.
  • A future. This describes work that has not run — add 'complete'. Making futures Printable compiles and prints a description of the work, which is why the report never asks for it.
  • A choice whose cases carry no payload. The namespace’s body may be empty: declaring namespace Problems for Problem is Printable {} is the whole of what such a choice needs.
  • A type that mentions type parameters. Declare a Namespace '<infer T> for (_: T) -> T is Printable'. The namespace stands outside the function that names T, so it declares T itself, inferred from the value: namespace Shown<infer T> for (_: T) -> T is Printable { … }. Where the type parameter stands in a bounded position of a choice, as Item in Ranked<Item> of choice Ranked<Value is Equatable>, the help adds the bound as a condition: … is Printable where Item is Equatable.
  • An overloaded function. No type annotation can spell it, so no namespace is offered, and a note says so: No Namespace can be declared for an overloaded Function — no Type Annotation can spell it, so no 'for' clause can name it.
  • An unbounded type parameter. Declare it as '<infer Item is Comparable>', with a Quick Fix that writes the bound onto a declaration in this file.

A namespace’s own type parameters are the exception to the last one: the bound goes on a method rather than on the declaration, and the report says which method — Bound it for this Method: write '<Item is Comparable>' after the Method's name, with a Quick Fix that writes it there. A method that FULFILS a protocol requirement is the exception to THAT: the conformance promised it unconditionally, so the condition belongs on the conformance (Add 'where Item is Comparable' to 'is Printable' on this Namespace.) and no per-method edit is offered, because one written there is refused. See protocol-bound-namespace-generic.

A parameter that already carries a bound is a third answer: a type parameter takes ONE bound, so neither edit is offered and the notes say the rule and the one way around it — a protocol that extends both.

A bound is the protocol the function’s own module resolved, so a call needs no import of it. What the call needs in scope is the conformance: a namespace that declares it, or the choice whose conformance is derived. This report spells the protocol the way the file does, under an import alias where it has one. Where the file has no name for it, an edit that writes the protocol needs its import as well: the Help names the module, 'Sized' is declared in Sized.es — import it here., and the Quick Fix writes the entry beside the bound. Where that module keeps the protocol private, the Help asks for the export too and no fix is offered. Where the file binds that name to something other than a type parameter, the Help asks for the import under a name of its own, 'Sized as …', written in the bound or the namespace, and no fix is offered.

Where the name the report spells is the file’s name for another protocol, a note says so: 'Sized' here is the Protocol this file declares; the bound asks for the 'Sized' that Sized.es declares. Where the two modules share a file name, each is named by the path this file would import it by, such as ./other/Sized.es. A second note names each namespace in scope that conforms to the file’s protocol of that name instead, since that is the conformance the call was meant to use. Where the file gives the name to a type, a function, a namespace or a value instead, the note names that: 'Sized' here is a Type; the bound asks for the Protocol 'Sized' that Sized.es declares. A type parameter of that name gets no note, since it can take the protocol as its bound.

Taught on: Protocols › Declared, not structural

interpolation-not-printable

Error. A { … } hole in a string holds a value that does not conform to Printable. A union does not take Printable from its members, so Integer | String is not Printable although both members are. A union of number types is the exception.

[interpolation-not-printable]
Error: Integer | String can not be interpolated into a String
   ╭─┤ Show.es:3:15 │
   │
 3 │        <- "value: {value}"
   │                    ──┬──  
   │                      ╰──── this is Integer | String, which is not Printable
   │ 
   │ Help: Interpolate only Printable values; match an Optional or a Union apart first and interpolate each Case.
   │ 
   │ Note: Integer | String does not conform to 'Printable'.
───╯

Match the value apart and interpolate each case: case Integer { <- "value: {@}" } case String { <- "value: {@}" }.

A hole holding a future is a forgotten complete rather than a printing problem, and the report says so in the words every other missing-complete report uses:

[interpolation-not-printable]
Error: Future<Integer> can not be interpolated into a String
   ╭─┤ Report.es:8:27 │
   │
 8 │     Terminal.print("answer: {fetched()}")
   │                              ────┬────  
   │                                  ╰────── this is Future<Integer>, which is not Printable
   │ 
   │ Help: This describes work that has not run — add 'complete'.
   │ 
   │ Note 1: Future<Integer> does not conform to 'Printable'.
   │ Note 2: Integer is what a Future<Integer> answers with, once something waits for it.
───╯

The word is named only where it may stand — inside a body that answers a future, and at a program’s top level. Anywhere else the note says so, and the Help is to declare the enclosing function -> Future<…> and write the complete in the hole: the declaration alone leaves the hole holding a future, which reports exactly as before.

A hole holding a type parameter is a missing bound rather than a union to match apart — Item is neither an Optional to unwrap nor a union to take apart, so the Help is the bound instead. Which bound depends on the method: one that FULFILS a requirement is promised by the conformance, so its bound goes on the where, and any other method bounds the parameter for itself (<Item is Printable> after its name):

[interpolation-not-printable]
Error: Item can not be interpolated into a String
   ╭─┤ Boxes.es:6:18 │
   │
 6 │          <- "a box of {@.item}"
   │                        ───┬──  
   │                           ╰──── this is Item, which is not Printable
   │ 
   │ Help: Add 'where Item is Printable' to 'is Printable' on this Namespace.
   │ 
   │ Note 1: Type Parameter 'Item' does not conform to 'Printable'.
   │ Note 2: 'Item' is 'Boxes's own Type Parameter, and this Method fulfils 'Printable' — so the bound belongs on the conformance, which promises the Method under it.
───╯

Quick Fix: Wait for it with ‘complete’, where the word may stand. There is none for any other unprintable hole: what to write there is a match or a bound, and neither is an edit to the hole.

Taught on: Unions and type aliases › Using a union before a match

redundant-interpolation-to-string

Warning. A { … } hole calls toString() on a value that is already Printable. The hole converts it the same way.

[redundant-interpolation-to-string]
Warning: A String Interpolation calls 'toString' on its own
   ╭─┤ Count.es:4:24 │
   │
 4 │     Terminal.print("{count::toString()} items")
   │                      ──┬────────┬─────  
   │                        ╰────────│─────── this is Integer, which is Printable
   │                                 │       
   │                                 ╰─────── this call is redundant
   │ 
   │ Help: Drop the '::toString()' and interpolate the value itself.
   │ 
   │ Note: A hole renders its value through its 'Printable' conformance — the same Method this call names.
───╯

Interpolate the value itself: "{count} items".

Quick Fix: Remove the redundant ‘toString’ call.

Taught on: Programs and values › Strings

ambiguous-conformance

Error. More than one namespace makes the type conform to the protocol, and none of them targets it more closely than the others.

[ambiguous-conformance]
Error: More than one Namespace makes { x: Integer, y: Integer } conform to 'Printable'
    ╭─┤ Point.es:18:19 │
    │
 18 │     Terminal.print("{here}")
    │                      ──┬─  
    │                        ╰─── the conformance can not be chosen here
    │ 
    │ Note 1: 'Plain' conforms to 'Printable'.
    │ Note 2: 'Fancy' conforms to 'Printable'.
────╯

Keep one of the conforming namespaces.

Taught on: Protocols › Unions in a bound

nonconforming-namespace

Error. A namespace declares a conformance but does not provide what the protocol requires. The label names the missing method.

[nonconforming-namespace]
Error: Namespace 'Points' does not conform to 'Printable'
   ╭─┤ Point.es:4:32 │
   │
 4 │     namespace Points for Point is Printable {}
   │                                   ────┬────  
   │                                       ╰────── Method 'toString' is missing
   │ 
   │ Help: Write 'toString' as 'Printable' declares it, or drop the 'is Printable'.
───╯

Write the missing method, here toString() -> String { … }. A choice whose cases carry no payload gets is Printable without writing a method. A method another protocol of the namespace provides answers the requirement only where its signature fulfils it; where it does not, a Note names that protocol. Where the requirement written as declared does not fulfil that protocol’s method either, writing it would refuse that conformance instead, so a second Note says the two protocols declare the method apart, the Help sends the conformance to a namespace of its own, and no stub is offered. A call that the missing method refuses reports this code too, with a Note naming the method the namespace does not write. The Help names every requirement the conformance owes, not only the one the label stopped at — a namespace that declares a conformance and writes nothing owes all of them.

Four other shapes report under the same code:

  • A method whose signature does not match. Write 'toString' with the signature 'Printable' declares for it. No stub is offered: this is a method to correct rather than one to write.
  • A method that needs a where condition. Add 'where Item is Printable' to this conformance. — unless that type parameter already carries a bound here, in which case a second one is refused and the Help sends the conformance to a namespace of its own instead.
  • A call whose value is narrower than the target type. The label reads this needs Integer to conform. A method, or a body another protocol provides, answers for the whole target type, such as make() -> Integer | String, where the call binds Self to Integer alone. For a body, a Note says where it narrows, 'describe' runs the body 'Shown' provides, whose Parameter 1 is 'Self': at Integer it takes an Integer, where 'Sized' accepts any Number., and the Help offers to take Number in the body or to declare a namespace for Integer. For a method the namespace writes, the Note says what it answers there, 'next' in 'Cyc' answers an Integer | String at Integer, where 'Cycled' answers an Integer., and the Help offers to declare a namespace for Integer. Where the value is a bare case, the Help asks for it to be annotated at its choice instead, leading with the import of a choice the file has no name for. Where the namespace covers more than that choice, the Help also asks for a namespace for the choice, since the covering one answers no Self of it either. For a body that reads a method the namespace answers for the whole target type, the Note names it, 'twin' runs the body 'Maker' provides, which reads 'make': at Integer 'NumberAll' answers it with a Number, where 'Maker' answers an Integer., and the Help offers to declare a namespace for Integer.
  • A method that runs one body for a protocol and another for one it extends. A value bounded by Both can be handed to a bound on Halved, where it runs the body it runs for Both, so a namespace conforming to both has to answer them with one body. The label reads Method 'z' runs one body for 'Both' and another for 'Halved', a Note names both bodies, 'z' runs the body 'Counted' provides for 'Both', and the body 'Halved' provides for 'Halved'., and the Help asks to write the method in the namespace as the extending protocol declares it. Where another protocol of the namespace declares the method apart, a Note names it and the Help first moves its conformance to a namespace of its own.

Quick Fix: Implement ‘Printable’ writes an empty method for each missing requirement, as name() -> String {} on one line — the shape esfmt leaves alone, so what the fix wrote is what a reader commits.

Taught on: Protocols › Declaring a protocol

undeclared-conformance

Error. A namespace over a choice writes a requirement of a protocol that the choice derives, such as is for Equatable, without declaring the conformance. A call through the protocol would reach the derived method instead of this one.

[undeclared-conformance]
Error: Namespace 'Colours' writes 'is' without declaring 'is Equatable'
   ╭─┤ Colour.es:8:3 │
   │
 8 │        is(_ other: Colour) -> Boolean {
   │        ─┐  
   │         ╰── Colour derives 'Equatable' unless this Namespace declares it
   │ 
   │ Help: Declare the conformance: 'is Equatable' on this Namespace.
   │ 
   │ Note: A call naming this Namespace answers what is written here; a call through an 'Equatable' bound answers the derived one.
───╯

Declare the conformance: namespace Colours for Colour is Equatable.

Quick Fix: Declare the conformance: ‘is Equatable’.

Taught on: Protocols › Derived conformances for choices

conformance-needs-target-type

Error. A namespace without a target type declares a conformance.

[conformance-needs-target-type]
Error: Only a Namespace with a target Type can conform to a Protocol
   ╭─┤ Tools.es:2:21 │
   │
 2 │     namespace Tools is Printable {}
   │                        ────┬────  
   │                            ╰────── this Namespace has no 'for …'
   │ 
   │ Note: A conformance says what a Type can do, so there has to be a Type.
───╯

Give the namespace a target type with for …, and write the methods the protocol requires.

Taught on: Protocols › Declaring a protocol

default-on-protocol-method

Error. A parameter of a protocol method has a default. A default belongs to each namespace’s method, not to the protocol.

[default-on-protocol-method]
Error: A Protocol requirement can not carry a default
   ╭─┤ Greeter.es:3:32 │
   │
 3 │        greet(times count: Integer = 1) -> String
   │                                     ▲  
   │                                     ╰── this default
   │ 
   │ Help: Declare the requirement without the default, and write the default on the fulfilling Method.
   │ 
   │ Note: A requirement says which calls a conforming Type must answer; a default is part of how one of them answers, which is each Namespace's own.
───╯

Remove the default from the requirement, and write it on the method that fulfils it. That method may carry a default its requirement does not.

A provided method, one with a body, is refused the same way, as “A provided Method can not carry a default”. A namespace may replace it, and a call through a bound then runs the replacement, which the default would not reach. The Help is to remove the default and pass the argument at each call.

Quick Fix: Remove the default.

Taught on: Protocols › What a requirement can be

protocol-bound-function-value

Error. A function with a protocol-bound type parameter is stored as a value. Such a function can only be called directly.

[protocol-bound-function-value]
Error: A Function with Protocol-bound Type Parameters can not be used as a value
   ╭─┤ Largest.es:6:21 │
   │
 6 │     constant measure = largest
   │                        ───┬───  
   │                           ╰───── this Function is stored, not called
   │ 
   │ Help: Invoke it, or wrap the call in a Function literal written for the Types you mean.
   │ 
   │ Note: A bounded Function carries hidden conformance Parameters that only exist at a direct invocation.
───╯

Call it, or wrap the call in a function literal: (_ items: List<Integer>) -> Integer { <- largest(of items) }.

Taught on: Functions as values › Methods and generic functions as values

overloaded-function-value

Error. An overloaded function, such as loop, is used as a value. Its name stands for several signatures, not one function.

[overloaded-function-value]
Error: An overloaded Function can not be used as a value
   ╭─┤ Loop.es:2:20 │
   │
 2 │     constant repeat = loop
   │                       ──┬─  
   │                         ╰─── this names all 9 overloads at once
   │ 
   │ Help: Invoke it, or wrap the overload you mean in a Function literal.
───╯

Wrap the overload you mean in a function literal, and store that: constant sumTo = (_ last: Integer) -> Integer { <- loop(from 1, through last, startingWith 0, (index, sum) { <- sum::add(index) }) }.

Taught on: Functions as values › Methods and generic functions as values

protocol-bound-namespace-generic

Error. A namespace’s type parameter carries a protocol bound, as in namespace Boxes<infer Item is Comparable>.

[protocol-bound-namespace-generic]
Error: A Namespace's Type Parameters can not carry Protocol bounds
   ╭─┤ Boxes.es:2:32 │
   │
 2 │     namespace Boxes<infer Item is Comparable> for List<Item> is Printable {
   │                                   ─────┬────  
   │                                        ╰────── this bound is not supported here
   │ 
   │ Help 1: Bound it on each Method that needs it: write '<Item is Comparable>' after that Method's name.
   │ Help 2: A Method that fulfils 'Printable' can carry no bound of its own, so bound it on the conformance instead: 'is Printable where Item is Comparable'.
   │ 
   │ Note 1: A bound written here would apply to every Method of 'Boxes', including the ones that do not need it.
   │ Note 2: A 'where' condition reaches the Methods that fulfil its conformance, which is the part a bound on the Namespace itself could never say.
───╯

A bound written on the namespace would apply to every method it holds, and to every receiver of its target shape. The two places that carry one each reach exactly what they are about.

Move it to the methods that need it: biggest<Item is Comparable>() -> Optional<Item>. The parameter is still the namespace’s — still worked out from the receiver, still written without infer — and the bound holds for that method alone.

A method that fulfils a conformance can not take that edit: the conformance promised it unconditionally, so a bound of its own is refused. Its bound goes into a conditional conformance instead: namespace Boxes<infer Item> for { value: Item } is Printable where Item is Printable. A where reaches the methods that fulfil that conformance and no others, so it bounds a whole family at once. The two Helps are not alternatives: a namespace whose fulfilling methods and other methods both need the bound takes both edits. The second Help appears only where the namespace already declares a conformance, and names it, because the condition belongs on one this namespace owes rather than on one it would then be reported for not writing. It spells each clause whole: one that has a where already takes the bound as one more condition, is Printable where Other is Printable, Item is Comparable, and a namespace with several conformances gets every one of them. A clause whose where already binds that type parameter to another protocol takes no second bound, so for it the help asks for the conformance on a namespace of its own, as nonconforming-namespace does.

Taught on: Protocols › Conditional conformance

shadowed-type-parameter

Error. A method names one of its namespace’s type parameters again, with no bound.

[shadowed-type-parameter]
Error: 'Item' is already this Namespace's Type Parameter
    ╭─┤ Conformance.es:39:8 │
    │
 39 │        held<Item>() -> Item {
    │             ──┬─  
    │               ╰─── 'Shadowing' declares 'Item' already
    │ 
    │ Help: Drop 'Item' from 'held's Type Parameters.
    │ 
    │ Note: 'Item' is worked out from the receiver at every call to 'held', so a second one here could only shadow it — and nothing would ever bind that.
────╯

There is one Item, the namespace’s, and the receiver decides it at every call. An entry that names it again with nothing to say declares a second one that carries no infer — so no call could ever bind it, the method asked for an argument of a type nothing produces, and every call to it answered no-matching-overload instead.

Drop the entry, or give it the bound that made you write it: held<Item is Printable>().

Taught on: Protocols › Conditional conformance

restated-inferred-parameter

Error. A method’s bound on its namespace’s type parameter restates infer.

[restated-inferred-parameter]
Error: 'Item' is already inferred by this Namespace
    ╭─┤ Conformance.es:47:9 │
    │
 47 │        shown<infer Item is Printable>() -> String {
    │              ───────────┬───────────  
    │                         ╰───────────── 'infer' belongs on 'Restating's own declaration, where it is
    │ 
    │ Help: Write '<Item is Printable>' on 'shown'.
    │ 
    │ Note: A Method bounds a Type Parameter it shares rather than declaring one of its own, so '<Item is Printable>' is the whole of what 'shown' has to say about it.
────╯

infer says where a type parameter’s type comes from, and the namespace already said it. A method bounding that parameter is adding a requirement, not declaring anything, so it writes the bound and nothing else. Drop the word.

Taught on: Protocols › Conditional conformance

unknown-where-generic

Error. A where condition names something that is not one of the namespace’s type parameters.

[unknown-where-generic]
Error: 'Other' is not a Type Parameter of this Namespace
   ╭─┤ Pairs.es:2:84 │
   │
 2 │     namespace Pairs<infer Item> for { first: Item, second: Other } is Printable where Other is Printable {
   │                                                                                       ──┬──  
   │                                                                                         ╰──── no such Type Parameter
   │ 
   │ Help: Declare it in the Namespace's Generic list: '<infer Other>'.
───╯

Fix the name, or declare the parameter in the namespace’s list. Declaring it is offered only where the target type names it, as second: Other does here. A target type that never names it could not prove the condition, which is unwitnessable-where-condition. There the help names the type parameter the name is a near miss of, as Item for Itme, and otherwise says to drop the condition.

Quick Fix: Declare it as ‘<infer Other>’, where the target type names it, or Change to ‘Item’ for a near miss.

Taught on: Protocols › Conditional conformance

conflicting-where-condition

Error. A where clause binds the same type parameter twice.

[conflicting-where-condition]
Error: 'Item' is bound twice in this conformance
   ╭─┤ Wrapper.es:3:43 │
   │
 3 │        is Comparable where Item is Comparable, Item is Equatable
   │                                                ──┬─  
   │                                                  ╰─── already bound to 'Comparable'
   │ 
   │ Help: Drop this condition, or declare 'is Comparable' on a Namespace of its own where 'Item is Equatable' is the one condition.
   │ 
   │ Note 1: 'Item' is already required to conform to 'Comparable'.
   │ Note 2: A conformance threads one witness per Type Parameter into the Methods that fulfil it, and one witness can not be two Protocols.
───╯

Keep one condition for each type parameter. A namespace that needs a second bound on the same parameter declares that conformance on a namespace of its own.

Taught on: Protocols › Conditional conformance

unwitnessable-where-condition

Error. A where condition names a type parameter that the namespace’s target type never mentions, so no use of the namespace could prove it.

[unwitnessable-where-condition]
Error: 'Other' does not appear in this Namespace's target Type
   ╭─┤ Pairs.es:2:77 │
   │
 2 │     namespace Pairs<infer Item, infer Other> for List<Item> is Printable where Other is Printable {
   │                                                                                ──┬──  
   │                                                                                  ╰──── not part of the target Type
   │ 
   │ Help: Mention 'Other' in the target Type, or drop the condition.
   │ 
   │ Note: A condition is proven by the target Type at each use site — a Type Parameter the target never mentions has nothing to prove it with.
───╯

Bound a parameter the target type mentions: namespace Pairs<infer Item> for List<Item> is Printable where Item is Printable. Or drop the condition.

Taught on: Protocols › Conditional conformance

unsatisfied-conformance-condition

Error. A conditional conformance is needed at a call, and its where condition does not hold. A list of records is not Comparable, because its records are not.

[unsatisfied-conformance-condition]
Error: List<{ x: Integer }> does not conform to 'Comparable'
   ╭─┤ Sort.es:2:17 │
   │
 2 │     Terminal.print([[{ x = 1 }], [{ x = 2 }]]::sort())
   │                    ─────────────────┬────────────────  
   │                                     ╰────────────────── this binds a Type Parameter bound to 'Comparable'
   │ 
   │ Help: Declare a Namespace 'for { x: Integer } is Comparable'.
   │ 
   │ Note: { x: Integer } does not conform to 'Comparable'.
───╯

Make the item type conform to the protocol, as the Help shows. The Help names the last link of the chain — the type that actually has no conforming namespace, which the note names. A namespace declared for the outer type answers the one call and leaves every other list of that record unsorted.

A condition is solved where the call is, under the protocol its namespace resolved, so it needs no import of that protocol either. What has to be in scope is a namespace that meets it, as unsatisfied-bound says of a bound. Where the file gives the condition protocol’s name to another protocol, the note that says so reads the condition asks for rather than the bound asks for.

Taught on: Protocols › Conditional conformance

where-on-protocol-extension

Error. A protocol extension, such as protocol Ordered is Comparable, carries a where clause. A protocol declares no type parameters, so the condition has nothing to bound.

[where-on-protocol-extension]
Error: A Protocol extension can not carry a 'where' clause
   ╭─┤ Ordered.es:2:39 │
   │
 2 │     protocol Ordered is Comparable where Item is Comparable {
   │                                          ─────────┬────────  
   │                                                   ╰────────── this condition has nothing to bound
   │ 
   │ Help: Write 'is Comparable' on its own, and bound the Type Parameter where the conforming Namespace is declared.
   │ 
   │ Note: A 'where' condition bounds one of the declaring Namespace's Type Parameters, and a Protocol declares none.
───╯

Write is Comparable on its own.

Quick Fix: Drop the ‘where’ clause.

Taught on: Protocols › Extending a protocol

unwritable-provided-method

Error. A static method in a protocol has a body. A provided method runs on @, the conforming value, and a static method has none.

[unwritable-provided-method]
Error: A static Protocol Method can not carry a body
   ╭─┤ Sized.es:5:14 │
   │
 5 │ ╭─▶        static make() -> Integer {
 6 │ │            <- 0
 7 │ ├─▶        }
   │ │              
   │ ╰────────────── this body has no receiver to run on
   │ 
   │ Help: Write 'make' as a requirement, and give each conforming Namespace a body of its own.
   │ 
   │ Note: A provided Method is written on '@', the conforming value, and a static Method is called on the Namespace instead.
───╯

Write it as a requirement without a body, and give each conforming namespace its own.

Taught on: Protocols › What a provided body can call

recursive-protocol

Error. A protocol extends itself, directly or through other protocols.

[recursive-protocol]
Error: Protocol 'Listed' extends itself through 'Sorted'
   ╭─┤ Listed.es:2:21 │
   │
 2 │     protocol Listed is Sorted {}
   │                        ───┬──  
   │                           ╰──── this leads back to 'Listed'
   │ 
   │ Help: Break the cycle — drop one of the extensions.
   │ 
   │ Note 1: 'Listed' extends 'Sorted', which extends 'Listed' again.
   │ Note 2: A Protocol's surface is its own Methods together with every ancestor's, so one that extends itself would never finish resolving.
───╯

Drop one of the extensions.

Taught on: Protocols › Extending a protocol

incompatible-restatement

Error. A protocol that extends another restates one of its methods with a signature the other does not accept, such as tag() -> Integer for tag() -> String, or as an overload block.

[incompatible-restatement]
Error: Protocol 'Coded' restates 'tag' with a signature 'Labelled' does not accept
    ╭─┤ Protocols.es:97:3 │
    │
 97 │        tag() -> Integer {
    │        ─┬─  
    │         ╰─── 'Labelled' declares it as 'tag() -> String'
    │ 
    │ Help: Restate 'tag' with the signature 'Labelled' declares for it, 'tag() -> String', or give this Method a name of its own.
    │ 
    │ Note: Whatever conforms to 'Coded' conforms to 'Labelled' as well, so a call through 'Labelled' reaches this 'tag' and calls it as 'Labelled' declares it.
────╯

A value bounded by Coded can be handed to a function bounded by Labelled, and a call there reaches the restated method. So a restatement, with a body or as a requirement, keeps a signature the extended protocol accepts: the same one, or one that takes wider arguments or answers a narrower type. A call through Labelled reaches the one tag it declares, and an overload block keeps each of its signatures as an entry of its own, so an overload block restating one method is refused as well.

The same code reports a protocol that extends two others declaring one method where neither signature accepts the other, as protocol Tagged is Labelled, is Counted does where Counted declares tag() -> Integer. Where one of them accepts the other, as tag() -> Number accepts tag() -> Integer, the extending protocol takes the one accepted, in either clause order. The label names the clause the method comes from. Declare the method with one signature in both, or rename it in one of them.

A module that imports a refused protocol reports what the refusal breaks there as nonconforming-namespace, with a Note that names the refused protocol and the module that declares it.

Taught on: Protocols › Extending a protocol

method-not-on-protocol

Error. A method is called on a value whose type is a bounded type parameter, and the bounding protocol does not declare that method. Only the protocol’s methods are known.

[method-not-on-protocol]
Error: 'Sized' has no Method named 'toString'
   ╭─┤ Sized.es:7:12 │
   │
 7 │        <- item::toString()
   │           ──┬─  ────┬───  
   │             ╰───────│───── 'Item' is only known to conform to 'Sized'
   │                     │     
   │                     ╰───── 'Sized' does not declare this Method
   │ 
   │ Help: Declare 'toString' on 'Sized', or bound 'Item' by a Protocol that has it.
   │ 
   │ Note: 'Sized' declares 'size'.
───╯

Declare the method on the protocol, or bound the parameter by a protocol that has it, such as <infer Item is Printable>.

Taught on: Protocols › One bound per type parameter

provided-method-out-of-reach

Error. A provided method’s body reaches something the program declares: it names it, such as a constant, calls a method of the program’s namespace on a value, or needs a conformance the program’s namespace declares. A provided method can reach only the standard library.

[provided-method-out-of-reach]
Error: 'unit' can not be read from a provided Method
    ╭─┤ Protocols.es:33:22 │
    │
 27 │     constant unit = " unit"
    │              ──┬─  
    │                ╰─── 'unit' is declared here
    │ 
 33 │          <- "{@::amount()}{unit}{Sizes.suffix()}"
    │                            ──┬─  
    │                              ╰─── this is declared outside the Protocol
    │ 
    │ Help: Give 'Measured' a requirement the body calls on '@' instead, and let each conforming Namespace reach 'unit'.
    │ 
    │ Note: A provided Method is emitted once, above every Program that reaches 'Measured' — so its body can name the standard library and nothing the Program declares.
────╯

Add a requirement that the body calls on @, and let each conforming namespace supply the value.

A call such as @::size()::shout(), where the program’s namespace Helpers for Integer declares shout, is reported as “‘shout’ can not be called from a provided Method”, labelled “this calls the ‘shout’ that ‘Helpers’ declares”. A conformance the body needs is reported by the namespace that declares it: a string hole holding a value whose Printable conformance the program’s Boxes declares is “‘Boxes’ can not be reached from a provided Method”, labelled “this needs the ‘Printable’ conformance that ‘Boxes’ declares”. Both take the same Note, and a Help that moves the call into each conforming namespace.

Taught on: Protocols › What a provided body can call

Documentation comments

Warnings about §§ blocks. The program compiles either way.

missing-documentation-separator

Warning. A @param or @returns tag runs into its text without the em dash that separates them. JSDoc’s hyphen, as in @param _ - the number to double, does not count as a separator and reports this code too.

[missing-documentation-separator]
Warning: This '@param' tag is not separated from its text
   ╭─┤ Double.es:4:14 │
   │
 4 │     §§ @param _ the number to double
   │                 ──────────┬─────────  
   │                           ╰─────────── an em-dash belongs here
   │ 
   │ Help: Write '@param _ —' before the text.
   │ 
   │ Note 1: A tag carrying its text on its own line separates the two with an em-dash — that is where the description begins, and how an Editor renders the tag back. A tag that leaves its text to the lines below it needs no separator.
   │ Note 2: The text is lifted into the Documentation either way; what is missing is the separator, not the description.
───╯

Write — between the name and the text: §§ @param _ — the number to double.

Quick Fix: Insert the ‘—’ separator — which REPLACES a JSDoc hyphen where one was written, so that @param _ - the number becomes @param _ — the number rather than carrying both languages’ punctuation. A hyphen inside the description is left alone; only a run at the head of the text is that separator.

Taught on: Documentation comments › missing-documentation-separator

unknown-documentation-parameter

Warning. A @param line is written where the signature has no parameter, past the last one.

[unknown-documentation-parameter]
Warning: This '@param' names a Parameter that does not exist
   ╭─┤ Double.es:5:12 │
   │
 5 │     §§ @param by — how many times
   │               ─┐  
   │                ╰── there is no Parameter 2
   │ 
   │ Help: Remove the tag — this signature takes 1 Parameter.
   │ 
   │ Note 1: A '@param' line documents the Parameter at its own position — the first line the first Parameter — and names it the way the signature does: its label, or '_' where it carries none.
   │ Note 2: The Parameters are '_', in that order.
───╯

Remove the line, or add the parameter it describes.

Quick Fix: Remove the ‘@param’ line. Above an overload block, a close name gets Change to ‘@param x’ as well. Removing the LAST tag takes the block’s empty §§ separator with it, rather than leaving a block that ends on a separator with nothing behind it.

Taught on: Documentation comments › unknown-documentation-parameter

misnamed-documentation-parameter

Warning. A @param line names a different parameter from the one at its position. The lines document parameters in order, and name each by its label, or by _ when it has none.

[misnamed-documentation-parameter]
Warning: This '@param' does not name the Parameter at its position
   ╭─┤ Double.es:4:12 │
   │
 4 │     §§ @param number — the number to double
   │               ───┬──  
   │                  ╰──── Parameter 1 is 'number'
   │ 
   │ Help: Write '@param _' — Parameter 1 carries no label.
   │ 
   │ Note 1: A '@param' line documents the Parameter at its own position — the first line the first Parameter — and names it the way the signature does: its label, or '_' where it carries none.
   │ Note 2: The Parameters are '_', in that order.
───╯

Write the label, or _: §§ @param _ — the number to double.

Quick Fix: Change to ‘@param _’.

Taught on: Documentation comments › misnamed-documentation-parameter

undocumented-parameter

Warning. A block that documents parameters leaves one out.

[undocumented-parameter]
Warning: This Parameter has no '@param' line
   ╭─┤ Scale.es:5:36 │
   │
 5 │     function scale(_ number: Integer, by factor: Integer) -> Integer {
   │                                       ─────────┬────────  
   │                                                ╰────────── Parameter 2 is undocumented
   │ 
   │ Help: Write '@param by — …' as line 2 of the run.
   │ 
   │ Note: A '@param' line documents the Parameter at its own position — the first line the first Parameter — and names it the way the signature does: its label, or '_' where it carries none.
───╯

Add a line for it: §§ @param by — the factor to scale it by.

Where another @param line on the same block already spells this parameter’s name, the two reports are one missing line seen from both ends, and the order they are answered in shows: a second note says which line to put right first, so that taking this fix alone does not leave two lines of the same name with nothing saying why.

Quick Fix: Add a ‘@param by’ line.

Taught on: Documentation comments › undocumented-parameter

nested-example

Warning. An @example documents a declaration nested inside a body, a suite or a test. Examples run beside the file’s top-level declarations, where a nested one is not in scope, so this one never runs.

[nested-example]
Warning: This '@example' of 'counted' never runs
   ╭─┤ Total.es:3:3 │
   │
 2 │     function total(of price: Integer, times quantity: Integer) -> Integer {
   │              ──┬──  
   │                ╰──── 'counted' is declared inside this
 3 │        §§ @example
   │        ─────┬─────  
   │             ╰─────── no test is made from this example
   │ 
   │ Help: Show it through an '@example' on the top-level declaration 'counted' is nested in, or remove the '@example' tag to keep these lines as prose.
   │ 
   │ Note: An '@example' runs as a test beside the file's top-level declarations, and a nested declaration is in scope only inside what declares it.
───╯

Show the behaviour through an example on total, or remove the @example line so the code stays in the block as prose. Inside a suite or a test, write the example as a test there.

Taught on: Documentation comments › Examples that run

Modules

Importing, exporting, and the graph of files.

invalid-module-specifier

Error. A specifier is not a relative path to a .es file. It starts with ./ or ../ and includes the extension, so Geometry.es and ./Geometry are both refused.

[invalid-module-specifier]
Error: Module specifier 'Geometry.es' is not a relative path

Write the path from this file: from "./Geometry.es" { area }.

Quick Fix: Write ‘./Geometry.es’.

Four things are refused under this one code, and each says something different:

What was written What is reported What the Help asks for
/Users/ada/shop/Geometry.es is an absolute path the path from this module, beginning with ./ or ../ and ending in .es
Geometry.es, lodash is not a relative path the same — and a .es specifier missing only its ./ is offered ./Geometry.es as a Quick Fix
./Geometry, ./shapes/ does not name a .es file ./Geometry.es, as a Quick Fix; a specifier ending in / is asked to name the file itself
./clock.js, ./data.json does not name a .es file nothing to edit — see below

A specifier that already carries an extension names a file of some other kind, and no edit to the specifier makes it a module: ./clock.js.es is a file nobody has. There is no Essence import for JavaScript at all. The interop runs the other way round — a JavaScript program embeds a built Essence one, with essence build --embed — so this branch offers no Quick Fix.

[invalid-module-specifier]
Error: Module specifier './clock.js' does not name a '.es' file
   ╭─┤ Main.es:2:7 │
   │
 2 │     from "./clock.js" { now }
   │          ──────┬─────  
   │                ╰─────── the extension is part of the path
   │ 
   │ Help: Essence imports '.es' Modules and nothing else — reach a JavaScript file from the JavaScript side instead, by embedding this Program with 'essence build --embed'.
   │ 
   │ Note: A specifier is read exactly as written — no extension is appended and no directory is tried — so what it names is what is read.
───╯

A path that lands inside the standard library is refused too, under the same code and a message of its own — The standard library is not importable. Everything it declares is in scope in every program already, so the Help asks for the whole from "…" { … } group to go.

Taught on: Modules › Specifiers are relative paths

module-not-found

Error. Nothing can be read at the path a specifier resolves to. A Note gives the absolute path it tried, here for a project in /Users/ada/shop.

[module-not-found]
Error: No Module was found at './Geometri.es'
   ╭─┤ Main.es:2:7 │
   │
 2 │     from "./Geometri.es" { area }
   │          ───────┬───────  
   │                 ╰───────── nothing could be read here
   │ 
   │ Help: Check the spelling of the path, and that the file is saved where it says.
   │ 
   │ Note: The specifier resolves to '/Users/ada/shop/Geometri.es'.
───╯

Fix the path, or save the file where the path says.

Taught on: Modules › Specifiers are relative paths

self-import

Error. A file imports itself. Everything a module declares is already in scope inside it.

[self-import]
Error: A Module can not import itself
   ╭─┤ Main.es:2:7 │
   │
 2 │     from "./Main.es" { area }
   │          ─────┬─────  
   │               ╰─────── this path names the file it is written in
   │ 
   │ Help: Remove the whole 'from "./Main.es" { … }' group — every name it asks for is in scope here already.
   │ 
   │ Note: Everything a Module declares is in scope inside it already, whether or not it is exported.
───╯

The whole group goes, not one entry: the report is on the specifier, and every name under it comes from the file it names. A name the module never declares is in scope nowhere, so the help names it instead — … and 'helper' is declared nowhere in it. — and once the group goes, its uses are reported as unknown-name. An entry that renamed one of the module’s own names, helper as h, leaves uses of h behind, so the help asks for 'helper' in place of 'h' as well.

Quick Fix: Remove the entry for “./Main.es”.

An export { … } block can name its own file the same way, and there the answer is the opposite one. Those names are declared here — the block has written the forwarding form of something it is entitled to publish — so they are written as bare entries instead, and the module goes on exporting them.

[self-import]
Error: A Module can not import itself
   ╭─┤ Main.es:8:7 │
   │
 8 │     from "./Main.es" { area }
   │          ─────┬─────  
   │               ╰─────── this path names the file it is written in
   │ 
   │ Help: Write 'area' as a bare entry: 'export { area }'.
   │ 
   │ Note: Everything a Module declares is in scope inside it already, whether or not it is exported.
───╯

Quick Fix: Write ‘area’ as a bare entry.

Taught on: Modules › Specifiers are relative paths

not-exported

Error. The module declares the name but does not export it. A name is private unless the export { … } block lists it.

[not-exported]
Error: 'area' is not exported by ./Geometry.es
   ╭─┤ Main.es:2:25 │
   │
 2 │     from "./Geometry.es" { area }
   │                            ──┬─  
   │                              ╰─── declared in that Module, but private
   │ 
   │ Help: Add 'area' to the 'export { … }' block of ./Geometry.es.
   │ 
   │ Note: A name is private unless the Module's 'export { … }' block lists it.
───╯

Add the name to that module’s export { … } block.

Quick Fix: Export ‘area’ from ./Geometry.es, which edits the other file.

Two shapes get a different Help, because adding the name would be the wrong edit for both. A module that publishes the declaration under another name is asking to be imported by that name — adding this one would publish one function twice — and a second Note says why a block that plainly lists the declaration still keeps this name private:

   │ Help: ./Geometry.es exports it as 'squareArea' — import that name instead: 'squareArea as area'.
   │ 
   │ Note 1: A name is private unless the Module's 'export { … }' block lists it.
   │ Note 2: An 'as' on an export entry renames the declaration for everyone, so a name the block lists under another one stays private under this one.

The entry it spells keeps the name this file reads, squareArea as area, so no use of area below the import has to change.

A module with no export block at all — or an empty one — has nothing to add to, so the Help asks for the block: Open an ‘export { … }’ block in ./Geometry.es and list ‘area’ in it.

Taught on: Modules › Importing names

unknown-export

Error. The module exports nothing under that name. An import is matched against the names a module exports.

[unknown-export]
Error: ./Geometry.es declares nothing named 'volume'
   ╭─┤ Main.es:2:25 │
   │
 2 │     from "./Geometry.es" { volume }
   │                            ───┬──  
   │                               ╰──── no such name in that Module
   │ 
   │ Help: Check the spelling, and that the specifier names the file you meant.
   │ 
   │ Note: The name is matched against what that Module exports, under the names it exports them as — an 'as' on its export entry renames it for everyone.
───╯

Fix the name or the path.

A near miss against what the module really publishes is answered, and offered as a Quick Fix:

[unknown-export]
Error: ./Geometry.es declares nothing named 'aera'
   ╭─┤ Main.es:2:25 │
   │
 2 │     from "./Geometry.es" { aera }
   │                            ──┬─  
   │                              ╰─── no such name in that Module
   │ 
   │ Help 1: Did you mean 'area'?
   │ Help 2: Check the spelling, and that the specifier names the file you meant.
   │ 
   │ Note: The name is matched against what that Module exports, under the names it exports them as — an 'as' on its export entry renames it for everyone.
───╯

Quick Fix: Change to ‘area’.

Taught on: Modules › Exporting names

duplicate-import

Error. An import binds a name that is already taken in this module.

[duplicate-import]
Error: 'area' is already declared here
   ╭─┤ Main.es:2:25 │
   │
 2 │     from "./Geometry.es" { area }
   │                            ──┬─  
   │                              ╰─── this binds 'area' a second time
   │ 
 6 │     constant area = 4
   │              ──┬─  
   │                ╰─── first declared here
   │ 
   │ Help: Write 'as' on the entry to bind it under another name — 'area as …'.
   │ 
   │ Note: An import binds a name in this Module exactly as a declaration does, so two of them can not share one.
───╯

Import it under another name: from "./Geometry.es" { area as tileArea }.

Quick Fix: Remove the duplicate import of ‘area’, when the name is imported twice — offered, never applied on its own. Two entries binding one name from two different modules are two different functions, and dropping the second leaves every call in the file reading the first.

Taught on: Modules › Importing names

export-of-unknown-name

Error. An export { … } entry names something this module does not declare.

[export-of-unknown-name]
Error: 'volume' is not declared in this Module
   ╭─┤ Geometry.es:5:10 │
   │
 5 │ export { volume }
   │          ───┬──  
   │             ╰──── nothing here declares this name
   │ 
   │ Help: Declare 'volume' in this Module, or remove the entry.
   │ 
   │ Note: An entry with no 'from' clause exports something this Module's implementation declares.
───╯

Declare the name, or stop exporting it.

Where one of this module’s own dependencies publishes the name, forwarding is an answer and the Help spells the specifier rather than a placeholder: Forward it from the Module that declares it: ‘from “./Money.es” { Money }’.

Quick Fix: Forward ‘volume’ from ./Solids.es, when a module in the workspace exports the name.

Taught on: Modules › Exporting names

export-of-variable

Error. An export { … } entry names a variable. JavaScript’s export let gives importers a live binding, so another module would read a value that can change under it. Essence refuses the export instead.

[export-of-variable]
Error: Variable 'count' can not be exported
   ╭─┤ Counter.es:5:10 │
   │
 2 │     variable count = 0
   │              ──┬──  
   │                ╰──── declared here
   │ 
 5 │ export { count }
   │          ──┬──  
   │            ╰──── this is a Variable
   │ 
   │ Help: Declare it as a Constant, or export a Function that answers with its value.
   │ 
   │ Note: A Variable another Module can read is state two files share and neither owns — which of them last wrote it is not something either one states.
───╯

Declare it as a constant, constant count = 0, or export a function that returns its value: function currentCount() -> Integer { <- count } and export { currentCount }.

Quick Fix: Declare ‘count’ as a Constant.

Where something in the module assigns to the variable, the first half is withheld and so is the fix — Help: Export a Function that answers with its value. Rewriting the declaration there answers constant-reassignment at every assignment, and that diagnostic asks for the variable back.

Taught on: Modules › Exporting names

cyclic-constant-import

Error. A module reads a constant from a module of its own import cycle, and the modules of the cycle wait on each other. A constant written without its type takes its value’s, which is known only once the value has been read. So the compiler reads each module of a cycle from the top, and a statement that reads such a constant of another module of the cycle waits until that module has been read down to the constant. Here the other module reads a constant of this one above its own constant, and that constant is declared below the read.

[cyclic-constant-import]
Error: Constant 'STEP' is read before ./Pong.es declares it
   ╭─┤ Ping.es:8:17 │
   │
 2 │     from "./Pong.es" { STEP }
   │                        ──┬─  
   │                          ╰─── imported from a Module of this cycle
   │ 
 8 │        <- value::add(STEP)
   │                      ──┬─  
   │                        ╰─── this needs the Type of 'STEP'
   │ 
   │ Help 1: Annotate 'STEP' with its Type in ./Pong.es: 'constant STEP: Type = …'.
   │ Help 2: Or declare 'STEP' above the Statements of ./Pong.es that read a Constant of this cycle, or move it into a Module outside the cycle.
   │ 
   │ Note 1: ./Pong.es imports this Module back, directly or through further Modules.
   │ Note 2: A Constant does not hoist, and one written without its Type takes its value's, known only once its Module has been read down to it. ./Pong.es reads a Constant of this cycle before it has declared 'STEP', and that Constant waits on this Module's code from this Statement on.
───╯

Write the constant with its type, here constant STEP: Integer = 2 in Pong.es. Its type is then known before its statement is read, and nothing waits for it. Declaring the constant above the other module’s statements that read a constant of the cycle works too, as does moving it into a module outside the cycle. A constant read across a cycle inside a function body is fine otherwise. A read while a module loads is cyclic-load-time-use.

Taught on: Modules › Run order and cycles

cyclic-load-time-use

Error. Code that runs while a module loads uses a name from a module of its own import cycle. That code is a constant’s value, a static property’s value or a top-level statement, and the functions they call. Inside a cycle, the order the modules load in is not stated, so the other module may not have run yet: its namespaces do not exist and its functions may read values it has not set.

[cyclic-load-time-use]
Error: 'pong' is used while this Module loads, but comes from a Module of its import cycle
    ╭─┤ Ping.es:10:21 │
    │
  2 │     from "./Pong.es" { pong }
    │                        ──┬─  
    │                          ╰─── bound from ./Pong.es here
    │ 
 10 │     constant opening = pong()
    │                        ──┬─  
    │                          ╰─── this calls it
    │ 
    │ Help: Use it inside a Function that runs once the Modules have loaded, or break the cycle.
    │ 
    │ Note: ./Pong.es imports this Module back, directly or through further Modules, so it may load after this one.
────╯

Make the value a function the program calls once the modules have loaded, such as function opening() -> String { <- pong() }, or move one of the two declarations out of the cycle. A function body that uses the other module is fine, as long as nothing calls it while a module of the cycle loads.

Taught on: Modules › Run order and cycles

cyclic-side-effects

Warning. A module in a cycle runs a statement at its top level, such as a print. Inside a cycle, the order the modules run in is not stated.

[cyclic-side-effects]
Warning: This Statement runs in an order the cycle does not state
    ╭─┤ Ping.es:10:2 │
    │
 10 │     Terminal.print("Ping.es runs")
    │     ───────────────┬──────────────  
    │                    ╰──────────────── this runs when the Module body runs
    │ 
    │ Help: Break the cycle, or move the Statement into a Module outside it.
    │ 
    │ Note 1: This Module is in a cycle with ./Pong.es.
    │ Note 2: A Module body runs once, on first import. Inside a cycle there is no first — whichever Module is reached first runs first, and that is decided by the entry point rather than by any of them.
────╯

Move the statement into a module outside the cycle, or break the cycle.

Taught on: Modules › Run order and cycles

unused-import

Warning. Nothing in the module reads an imported name. A namespace counts as used when a call runs one of its methods, and a call refused for want of a conformance still counts the namespaces it would have used.

[unused-import]
Warning: 'area' is imported and never used
   ╭─┤ Main.es:2:25 │
   │
 2 │     from "./Geometry.es" { area }
   │                            ──┬─  
   │                              ╰─── nothing reads this name
   │ 
   │ Help: Remove the entry.
───╯

Delete from "./Geometry.es" { area }, or read area in the file.

A Note says what else counts as a use, for a kind of import a file may use without spelling it: a namespace a call dispatches through, a choice whose case is written or whose derived conformance is reached, a refinement a narrowing proves. A constant, a function or a record type is used only where it is written, so it gets no Note.

A protocol entry is used where the file names it or calls a method it provides. A call to a function bounded by the protocol does not count, since the call needs no import of it.

Quick Fix: Remove the unused import of ‘area’. The Source Action Remove the unused imports removes every one in the file.

Taught on: Modules › Importing names

dependency-has-errors

Error. An imported module has errors of its own, reported on the import line — in the editor, so you see it without opening the other file, and in the terminal, which prints the other file’s own errors beside it. It is why a module nothing is wrong with does not compile.

It travels up the whole chain, re-exports included. With Main.es importing Middle.es importing Bottom.es, and the error in Bottom.es, Middle.es gets it on its import of Bottom.es and Main.es on its import of Middle.es, so every file names the import to follow. In a cycle, a module is not told about an import whose only problem leads back to the module itself.

Fix the errors in the imported module.

Taught on: Editor setup › Errors in closed files, and rename refusals

Tests

The tests { … } block and what runs in it.

misplaced-tests-section

Error. The tests { … } block is written above export { … } or above the implementation. It comes last in a file.

[misplaced-tests-section]
Error: The 'tests { … }' block belongs below the 'export { … }' block
    ╭─┤ Double.es:7:1 │
    │
  7 │ ╭─▶ tests {
    ┆ ┆   
 11 │ ├─▶ }
    │ │       
    │ ╰─────── this block is written above what the Module hands out
    │ 
 13 │     export { double }
    │     ───┬──  
    │        ╰──── the export block is here
    │ 
    │ Help: Move the 'tests { … }' block below 'export { … }'.
    │ 
    │ Note: A Module reads top to bottom: what it imports, what it does, what it exports, what it proves.
────╯

Move it below export { … }.

Quick Fix: Move the ‘tests { … }’ block to the end.

Taught on: Tests › The tests block

test-outside-tests

Error. A test or a suite is written outside the tests { … } block.

[test-outside-tests]
Error: A 'test' may only be written in the 'tests { … }' section
   ╭─┤ Double.es:2:2 │
   │
 2 │     test "doubles" {}
   │     ──┬─  
   │       ╰─── this 'test' stands outside every tests section
   │ 
   │ Help: Move it into the file's 'tests { … }' block, or open one below the implementation.
   │ 
   │ Note: The tests section is written below the implementation block, and a 'suite' groups the tests inside it.
───╯

Move it into the tests { … } block at the end of the file.

A test written inside another test’s body stands in the tests section already, so the report says A 'test' can not be written inside a test's body instead, and the Help moves it out beside that test or groups the two in a suite "…" { … }. One written in another block inside the tests section, such as a function’s body or an if in a suite, is told A 'test' can not be written inside a block, and the Help moves it out of the block.

Taught on: Tests › Tests and suites

expect-outside-test

Error. An expect or a require is written where no test is running, such as inside a function literal in a test’s body.

[expect-outside-test]
Error: 'expect' may only be written in a test's body
    ╭─┤ Double.es:10:4 │
    │
 10 │          expect double(number)::isPositive()
    │          ───┬──  
    │             ╰──── this assertion belongs to no test
    │ 
    │ Help: Move it into a 'test "…" { … }' block, or return the value and assert on it there.
    │ 
    │ Note: An assertion records its result against the test that is running, so it is a Statement of a test's own block and of the blocks nested in it — never of a Function literal written there.
────╯

Return the value from the function, and assert on it in the test’s own block.

Taught on: Tests › Tests and suites

expect-not-boolean

Error. An expect or a require asserts a value that is not a Boolean.

[expect-not-boolean]
Error: An assertion has to be a Boolean
   ╭─┤ Double.es:9:10 │
   │
 9 │        expect double(2)
   │               ────┬────  
   │                   ╰────── this is an Integer
   │ 
   │ Help: Ask a question of it: '::is(…)', '::isGreaterThan(…)'.
   │ 
   │ Note: Essence has no truthiness — an assertion is a Boolean Expression, and the standard library's own Methods are the vocabulary it is written in.
───╯

Ask a question of the value, expect double(2)::is(4), or take it apart with require #Value(item) = value. The help names only the questions the value’s own type answers, among ::is, ::isGreaterThan and ::hasItems, so an Integer is not offered ::hasItems(). A value that answers none of them, such as a function, is asked for a Boolean expression in its place.

Taught on: Tests › expect and require

matcher-on-expect

Error. An expect takes a value apart, as in expect #Value(first) = …. Only require introduces names, because a failed require ends the test.

[matcher-on-expect]
Error: An 'expect' can not take a value apart
   ╭─┤ Scores.es:7:10 │
   │
 7 │        expect #Value(first) = scores::firstItem()
   │               ──────┬──────  
   │                     ╰──────── this would introduce a name
   │ 
   │ Help 1: Take the value apart with 'require': 'require #Value(first) = scores::firstItem()'.
   │ Help 2: Or compare instead: 'expect scores::firstItem()::is(…)'.
   │ 
   │ Note: An 'expect' records its result and the test carries on, so a name it introduced would stand below a line that may never have run. A 'require' ends the test where it stands, which is what makes the names it introduces safe to read.
───╯

Write require #Value(first) = scores::firstItem(), then assert on first.

Quick Fix: Take the value apart with ‘require’.

Taught on: Tests › Taking a value apart

matcher-after-value

Error. A matcher is written after the value, behind is, as in require scores::firstItem() is #Value(first). A name is introduced left of =.

[matcher-after-value]
Error: An assertion has no 'is' form
   ╭─┤ Scores.es:7:31 │
   │
 7 │        require scores::firstItem() is #Value(first)
   │                                    ────────┬───────  
   │                                            ╰───────── this Matcher stands after the value
   │ 
   │ Help 1: Take the value apart with 'require': 'require #Value(first) = scores::firstItem()'.
   │ Help 2: Or compare instead: 'require scores::firstItem()::is(…)'.
   │ 
   │ Note: A name is introduced left of '=', in a Parameter, or in a Handler head — never on the right of anything.
───╯

Write require #Value(first) = scores::firstItem().

Quick Fix: Take the value apart with ‘require’.

Taught on: Tests › Taking a value apart

wildcard-in-require

Error. A require matches _, which every value matches and which binds nothing.

[wildcard-in-require]
Error: This 'require' asks nothing of the value
   ╭─┤ Scores.es:7:11 │
   │
 7 │        require _ = scores::firstItem()
   │                ▲  
   │                ╰── '_' holds for every value
   │ 
   │ Help: Name the shape the value has to have — a Case, a Type, a Pattern — or drop the line.
   │ 
   │ Note: A Matcher left of '=' both asks what the value has to be and names its parts, and '_' does neither: every value answers it, and it binds nothing.
───╯

Name the shape the value must have, such as #Value(first), or delete the line.

Taught on: Tests › Taking a value apart

literal-in-require

Error. A require matches a written value, as in require 3 = points. A matcher names a shape. Comparing with a value is is.

[literal-in-require]
Error: A written value has no parts to name
   ╭─┤ Points.es:7:11 │
   │
 7 │        require 3 = points
   │                ▲   ───┬──  
   │                ╰──────│──── this is a value, not a shape
   │                       │    
   │                       ╰──── the value it asks about
   │ 
   │ Help: Compare instead: 'points::is(3)'.
   │ 
   │ Note: 'require MATCHER = EXPR' takes a value apart by its shape — a Case, a Type, a Pattern. A written value is not a shape: what it asks is whether the two are equal, and that is what 'Equatable::is' answers.
───╯

Compare instead: require points::is(3).

Quick Fix: Compare it instead: ‘points::is(3)’.

Taught on: Tests › Taking a value apart

snapshot-after-matcher

Error. matches snapshot is written on a line that takes a value apart.

[snapshot-after-matcher]
Error: A snapshot records a value, and this line took one apart
   ╭─┤ Scores.es:7:47 │
   │
 7 │        require #Value(first) = scores::firstItem() matches snapshot
   │                                                    ────────┬───────  
   │                                                            ╰───────── there is no value here to record
   │ 
   │ Help 1: Record the name on a line of its own: 'require #Value(first) = scores::firstItem()' then 'expect first matches snapshot'.
   │ Help 2: Or snapshot the value whole, where it is one that prints: 'expect scores::firstItem() matches snapshot'.
   │ 
   │ Note: A snapshot is of the value an assertion is written over, printed as text. 'require MATCHER = EXPR' is written over a shape instead: it asks what the value has to be and names its parts, so what there is to record is one of those names.
───╯

Record the name on a line of its own: require #Value(first) = scores::firstItem(), then expect first matches snapshot. A matcher that names nothing, such as #Empty, leaves nothing to record but the value, so the first help asks for matches snapshot to go instead.

Quick Fix: Record ‘first’ on a line of its own.

Taught on: Tests › Taking a value apart

unknown-modifier

Error. A test or a suite carries a word that is not a modifier. The modifiers are focused, skipped and tagged.

[unknown-modifier]
Error: There is no Modifier 'slowly'
   ╭─┤ Table.es:6:25 │
   │
 6 │     test "ranks the table" slowly {
   │                            ───┬──  
   │                               ╰──── no such Modifier
   │ 
   │ Help: Remove it, or move what it was meant to say into the body — a Modifier is what the runner reads, never what the test does.
   │ 
   │ Note: A test takes 'focused', 'skipped', 'tagged'.
───╯

Remove the word, or fix its spelling.

Quick Fix: Remove ‘slowly’. A near miss gets Change to ‘focused’ first.

Taught on: Tests › Modifiers

duplicate-modifier

Error. A test or a suite carries the same modifier twice.

[duplicate-modifier]
Error: This test is 'tagged' twice
   ╭─┤ Table.es:6:37 │
   │
 6 │     test "ranks the table" tagged slow tagged network {
   │                            ─────┬───── ───────┬──────  
   │                                 ╰─────────────│──────── already written here
   │                                               │        
   │                                               ╰──────── written again here
   │ 
   │ Help: Write every tag on one 'tagged', separated by commas.
   │ 
   │ Note: A Modifier says something about the whole test, so saying it twice can only ever repeat it or contradict it.
───╯

Write every tag on one tagged, separated by commas: tagged slow, network. Any other modifier written twice is answered Remove one of them. — tagged is the only one that means something more when it is written again.

Quick Fix: Merge into one ‘tagged’. Another modifier written twice gets Remove the second ‘focused’.

Taught on: Tests › Modifiers

malformed-modifier

Error. A modifier has the wrong arguments. focused takes none, skipped takes one string, and tagged takes bare names.

[malformed-modifier]
Error: 'tagged' takes a bare name
   ╭─┤ Table.es:6:32 │
   │
 6 │     test "ranks the table" tagged "slow" {
   │                                   ───┬──  
   │                                      ╰──── this is not a bare name
   │ 
   │ Help: Write a bare name here.
   │ 
   │ Note: A tag is written the way it is typed on a command line — 'essence test --tag slow' — so it is a name rather than a value.
───╯

Write a tag as a bare name: tagged slow.

Five more shapes report the same code, each with its own message, label and Help. tagged with nothing after it names no tag, and a tagged that selects nothing is a modifier that does nothing:

[malformed-modifier]
Error: This is tagged with nothing
   ╭─┤ Table.es:4:25 │
   │
 4 │     test "ranks the table" tagged {
   │                            ───┬──  
   │                               ╰──── this names no tag
   │ 
   │ Help: Write the tags after it: tagged slow, network.
   │ 
   │ Note: A tag is what the command line selects on — 'essence test --tag slow' — so a 'tagged' naming none selects nothing.
───╯

A tag with a capital in it is a second tag. --tag and --skip-tag match exactly, so the spelling nobody selects is the one that quietly stops running:

[malformed-modifier]
Error: The tag 'Slow' is not lower case
   ╭─┤ Table.es:4:32 │
   │
 4 │     test "ranks the table" tagged Slow {
   │                                   ──┬─  
   │                                     ╰─── this has a capital in it
   │ 
   │ Help: Write it as 'slow'.
   │ 
   │ Note: A tag is matched exactly by '--tag' and '--skip-tag', so two spellings of one tag are two tags.
───╯

skipped takes a string, and nothing else stands for a reason:

[malformed-modifier]
Error: 'skipped' takes a String saying why
   ╭─┤ Table.es:4:33 │
   │
 4 │     test "ranks the table" skipped 3 {
   │                                    ▲  
   │                                    ╰── this is not a String saying why
   │ 
   │ Help: Write a String saying why here.
   │ 
   │ Note: The reason is what the report repeats on every run, so it is written for whoever reads that report.
───╯

A second reason is a second skip, and the edit is a deletion — the reader is standing on the thing that has to go, so this shape asks for that rather than for a reason to be written where one already is:

[malformed-modifier]
Error: 'skipped' takes one reason and nothing else
   ╭─┤ Table.es:4:44 │
   │
 4 │     test "ranks the table" skipped "waiting", "and waiting" {
   │                                               ──────┬──────  
   │                                                     ╰──────── this is not one reason and nothing else
   │ 
   │ Help: Remove the extra reason — 'skipped' carries one.
   │ 
   │ Note: A test is skipped for one reason. Two of them is two skips.
───╯

And focused says all of what it says by being written, so anything after it is read by nothing:

[malformed-modifier]
Error: 'focused' takes nothing
   ╭─┤ Table.es:4:33 │
   │
 4 │     test "ranks the table" focused "now" {
   │                                    ──┬──  
   │                                      ╰──── nothing reads this
   │ 
   │ Help: Remove it.
   │ 
   │ Note: 'focused' says one thing about the test, and says all of it by being written.
───╯

Taught on: Tests › Modifiers

skipped-without-reason

Error. A test or a suite is skipped with no reason.

[skipped-without-reason]
Error: This test is skipped for no stated reason
   ╭─┤ Table.es:6:25 │
   │
 6 │     test "ranks the table" skipped {
   │                            ───┬───  
   │                               ╰───── this needs a reason
   │ 
   │ Help: Write it as a String: skipped "waiting on the Table redesign".
   │ 
   │ Note: A skip with no reason rots silently. A skip with one is a note the report repeats on every run, until somebody acts on it.
───╯

Give the reason as a string: skipped "waiting on the table redesign".

Taught on: Tests › Modifiers

contradictory-modifiers

Error. A test or a suite is both focused and skipped.

[contradictory-modifiers]
Error: This test is skipped and focused
   ╭─┤ Table.es:6:25 │
   │
 6 │     test "ranks the table" focused skipped "flaky" {
   │                            ───┬─── ───────┬───────  
   │                               ╰───────────│───────── this asks for it to run, and alone
   │                                           │         
   │                                           ╰───────── this asks for it never to run
   │ 
   │ Help: Remove whichever one you did not mean.
   │ 
   │ Note: Which of the two was meant is not something the source says, and guessing at it is how a test nobody watches stops running.
───╯

Remove the one you did not mean, as in test "ranks the table" skipped "flaky" { … }.

Quick Fix: Remove ‘skipped’ or Remove ‘focused’.

Taught on: Tests › Modifiers

duplicate-test-name

Error. Two tests or two suites in one scope have the same name. A test’s name, with the suites around it, identifies it to snapshots and to the editor.

[duplicate-test-name]
Error: There is already a test called 'ranks the table' here
    ╭─┤ Table.es:10:7 │
    │
  6 │     test "ranks the table" {
    │          ────────┬────────  
    │                  ╰────────── the other test is here
    │ 
 10 │     test "ranks the table" {
    │          ────────┬────────  
    │                  ╰────────── this name is taken
    │ 
    │ Help: Say what each of them proves, so that a report names the one that failed.
    │ 
    │ Note: What a test is called, together with the suites around it, is what identifies it — to a snapshot, to a stored counterexample, and to the Editor.
────╯

Name each test by what it proves.

Taught on: Tests › Names and identity

test-failed

Error. An expect or a require did not hold while the test ran. essence test reports this, and so does the editor’s test session; a compile does not. The labels show the values the assertion saw.

[test-failed]
Error: 'doubles' failed
   ╭─┤ Double.es:9:10 │
   │
 9 │        expect double(3)::is(6)
   │               ────┬───┬───────  
   │                   ╰───│───────── 5
   │                       │         
   │                       ╰───────── this expect failed
   │ 
   │ Note: `is` compared 5 with 6
───╯

Fix the program or the test. The values in the labels show which one is wrong.

Taught on: Tests › expect and require

focused-tests-remain

Error. An essence test run with no --filter, --tag or --skip-tag finds a focused test. focused is Essence’s test.only. The run fails and names each focused test. In the editor, each focused gets a Warning.

[focused-tests-remain]
Error: This test is still focused
   ╭─┤ Double.es:8:2 │
   │
 8 │     test "doubles" focused {
   │     ──┬─  
   │       ╰─── only focused tests ran
   │ 
   │ Help: Remove 'focused' before this lands, or narrow the run with '--filter' or '--tag' while you are iterating.
   │ 
   │ Note: A focused test silences every other test of the run, so a run nobody narrowed has not answered the question it was asked.
───╯

Remove focused before you commit. While you iterate, narrow the run with --filter or --tag instead.

The two reports differ by one word, deliberately: the terminal says only focused tests ran, because it reports after the run, and the editor says only focused tests run, because it reports before there is one. The editor’s is a Warning on the focused keyword; the terminal’s is an Error on the test keyword, and it names every focused test of the run at once.

Quick Fix: Remove ‘focused’.

Taught on: Tests › Modifiers

similar-tags

Warning. Two tags in the workspace are nearly the same, such as netwrok and network. --tag matches a tag exactly, so the two spellings select two different sets of tests. The editor reports this; a compile does not.

Use one spelling.

Quick Fix: Change to ‘network’, which writes the common spelling over the rare one.

Taught on: Running tests

lonely-tag

Information. Exactly one test in the workspace carries a tag. That is allowed, and it is also what a mistyped tag looks like. The editor reports this; a compile does not.

If the tag is meant, leave it. Otherwise fix its spelling.

Taught on: Running tests

table-not-written

Error. The value after across is not a written list. Each row is a test of its own, so the rows must be countable before anything runs.

[table-not-written]
Error: The rows of a table test have to be written here
    ╭─┤ Double.es:10:33 │
    │
 10 │     test "doubles {number}" across numbers (number: Integer) {
    │                                    ───┬───  
    │                                       ╰───── this is not a written List
    │ 
    │ Help: Write the rows as a List: 'across [ … ] (number: Integer)'. A row itself can be any Expression.
    │ 
    │ Note: Every row is a test of its own — it carries its row number in the identity a stored snapshot and the Editor's own results are keyed by — so the rows have to be countable before anything runs.
────╯

Write the rows in the test: across [1, 2, 3] (number: Integer).

Taught on: Tests › Table tests

table-without-rows

Error. The list after across is empty, so the table test runs no test and nothing reports it.

[table-without-rows]
Error: A table test with no rows in it runs no test
   ╭─┤ Double.es:8:33 │
   │
 8 │     test "doubles {number}" across [] (number: Integer) {
   │                                    ─┐  
   │                                     ╰── no rows to run
   │ 
   │ Help: Write the rows the test is for, or say why there are none with 'skipped "…"'.
   │ 
   │ Note: Every row is a test of its own, so a table test with none is nothing at all: it is reported by no line and counted in no total, and nothing would say it had stopped running.
───╯

Write the rows. If there are none for now, mark the test skipped with the reason — test "doubles" skipped "no rows yet" across [] (number: Integer) { … } is accepted, and the skip is what the report carries instead.

Taught on: Tests › Table tests

table-parameters

Error. A table test names its row with more than one parameter, or gives the row parameter a default. Each row is one value, written whole.

[table-parameters]
Error: A table test takes one row at a time
   ╭─┤ Add.es:8:40 │
   │
 8 │     test "adds" across [{ a = 1, b = 2 }] (a: Integer, b: Integer) {
   │                 ───┬──                    ────────────┬───────────  
   │                    ╰──────────────────────────────────│───────────── the rows are here
   │                                                       │             
   │                                                       ╰───────────── 2 Parameters for one row
   │ 
   │ Help: Write one Parameter: '(row: { a: Integer, b: Integer })', or take the row apart where it is bound: '({ a, b }: { a: Integer, b: Integer })'.
   │ 
   │ Note: Each item of the List is one row, and one row is one value — a test that wanted several values per row would say so by writing a Record.
───╯

Take the row apart in one parameter: ({ a, b }: { a: Integer, b: Integer }). A default such as (n: Integer = 5) is never read, since no row leaves its value out. Remove it.

Taught on: Tests › Table tests

table-row-type-mismatch

Error. A row is not a value of the row parameter’s type.

[table-row-type-mismatch]
Error: This row does not fit the row Parameter
   ╭─┤ Double.es:8:37 │
   │
 8 │     test "doubles {number}" across [1, "two"] (number: Integer) {
   │                                        ──┬──  
   │                                          ╰──── this is a String
   │ 
   │ Help: Write a row of Type Integer, or widen the row Parameter's Type to one this row is a value of — a widened Type has to stay Printable, since this test's name interpolates the row.
   │ 
   │ Note: The row Parameter is declared as Integer, and that is the Type the body — and an interpolated name — reads every row under.
───╯

Write the row as the type says, or widen the parameter’s type.

Taught on: Tests › Table tests

snapshot-not-printable

Error. matches snapshot records how a value prints, and this value is not Printable. A choice is Printable only when a namespace declares it.

[snapshot-not-printable]
Error: Colour can not be recorded as a snapshot
    ╭─┤ Colour.es:12:10 │
    │
 12 │        expect favourite matches snapshot
    │               ────┬────  
    │                   ╰────── this is Colour, which is not Printable
    │ 
    │ Help 1: Declare a 'Printable' conformance for it — 'namespace … for Colour is Printable { … }'.
    │ Help 2: Or snapshot a String you build yourself.
    │ 
    │ Note 1: A snapshot records what a value LOOKS like, which is what 'Printable::toString' answers — so a value with no such answer has nothing to record.
    │ Note 2: Colour does not conform to 'Printable'.
────╯

Declare the conformance, namespace Colours for Colour is Printable {}, or snapshot a string you build yourself.

Two shapes are answered differently, because the conformance cannot be written for either. A bare case is not a type a namespace can target — namespace X for Colour#Red does not parse — so both edits are named: Declare a 'Printable' conformance for 'Colour' and annotate the value at it — a bare Case binds the Case, not the Choice. An overloaded function has no type at all, and gets the one answer that is left: Snapshot a String you build yourself — no Namespace can be declared for an overloaded Function. A function value is not such a shape: namespace Shown for (_: Integer) -> Integer is Printable { … } makes one printable, and the help says so.

Taught on: Tests › Snapshots

inline-snapshot-in-table

Error. An inline matches snapshot is written in a table test. Every row would record into the same place in the source.

[inline-snapshot-in-table]
Error: A snapshot in a table test has to be named
   ╭─┤ Double.es:9:25 │
   │
 9 │        expect double(number) matches snapshot
   │                              ────────┬───────  
   │                                      ╰───────── this records into the source, and every row would record here
   │ 
   │ Help: Name it: 'matches snapshot from "…"'. Each row records an entry of its own, numbered by the row it ran for.
   │ 
   │ Note: Every row of a table test runs this body, so a snapshot written here holds one value per row — and an inline snapshot is one slot of one line.
───╯

Name the snapshot, matches snapshot from "doubled", and each row records an entry of its own.

Taught on: Tests › Table tests

property-parameters

Error. A for any (…) parameter does not write both a name and a type. The type says which values to generate.

[property-parameters]
Error: A generated Parameter has to write its Type
   ╭─┤ Add.es:8:31 │
   │
 8 │     test "add commutes" for any (a, b: Integer) {
   │                                  ▲  
   │                                  ╰── nothing here says what to generate
   │ 
   │ Help: Write the Type: 'for any (a: …)'.
   │ 
   │ Note: The Type is the whole of what a generator is derived from.
───╯

Write a type for each parameter: for any (a: Integer, b: Integer). Nothing says which type a was meant to have, so the help leaves it as … for you to fill in.

Where the one word written is a type — for any (Integer) — the missing half is the name, and the Help asks for that instead: Write a name for it: 'for any (value: Integer)'. A pattern written in place of the name, as in for any ({ name }: Player), is asked to name the whole value at the type it was written with: 'for any (value: Player)', taken apart inside the body.

Taught on: Tests › Property tests

ungeneratable-type

Error. A for any (…) parameter has a type that nothing can generate, such as a function type.

[ungeneratable-type]
Error: Nothing can generate a (_ String) -> Integer
   ╭─┤ Read.es:8:37 │
   │
 8 │     test "every reader reads" for any (read: (_ text: String) -> Integer) {
   │                                        ────────────────┬────────────────  
   │                                                        ╰────────────────── nothing knows how to build a (_ String) -> Integer
   │ 
   │ Help 1: Write a Type a value can be built of, or declare a 'Generatable' conformance for this one.
   │ Help 2: Write 'shrink' in the conformance as well: 'Generatable' provides one that answers no candidates, and a counterexample is otherwise reported as it was drawn.
   │ 
   │ Note: A property test generates a value of every Parameter's Type, once per case.
───╯

Use a type that can be generated, or declare a Generatable conformance for it.

Quick Fix: Make ‘T’ Generatable writes the conformance for a record alias or a choice that this file declares.

Taught on: Tests › Property tests

unreachable-conformance

Error. A property test generates a type whose Generatable conformance is declared on a generic namespace. generate takes only a Randomness, so the compiler has nothing to infer the namespace’s type parameter from.

[unreachable-conformance]
Error: Namespace 'Pairs' is generic, so its 'Generatable' conformance can not be reached
    ╭─┤ Pair.es:22:35 │
    │
 22 │     test "a pair is marked" for any (pair: Pair<Twin>) {
    │                                      ────────┬───────  
    │                                              ╰───────── nothing here binds 'Item' for the draw
    │ 
    │ Help: Declare 'Generatable' on a Namespace whose target Type is already applied, rather than on a generic one.
    │ 
    │ Note 1: 'generate' is a static taking a 'Randomness' and nothing else, so a call has no Argument to work 'Item' out from — and a call can not be written with a Type Argument.
    │ Note 2: Passed over, the structural generator would draw and shrink a { held: { first: Integer, second: Integer }, mark: Integer } instead, which is what this conformance was written to replace.
────╯

Declare the conformance on a namespace for the applied type: namespace TwinPairs for Pair<Twin> is Generatable.

reserved-suite-name

Error. A suite uses a name that the compiler fills itself, such as examples in a file with @example blocks.

[reserved-suite-name]
Error: The suite name 'examples' is taken by this file's '@example' blocks
    ╭─┤ Double.es:14:8 │
    │
 14 │     suite "examples" {
    │           ─────┬────  
    │                ╰────── this names the synthesized suite
    │ 
    │ Help: Call this suite something else.
    │ 
    │ Note: Under this compile the Enricher fills a suite called 'examples' with this file's '@example' blocks, and two suites of one name share everything their identity anchors — stored counterexamples, seeds, and the Editor's focus.
────╯

Rename the suite.

Taught on: Tests › Names and identity

contradictory-test-forms

Error. One test writes both across and for any. A table test runs once per written row, and a property test runs once per generated value.

[contradictory-test-forms]
Error: A test runs written rows or generated values, not both
   ╭─┤ Double.es:8:50 │
   │
 8 │     test "doubling" across [1, 2] (number: Integer) for any (other: Integer) {
   │                     ───┬──                          ─┬─  
   │                        ╰─────────────────────────────│─── and this runs the rows
   │                                                      │   
   │                                                      ╰─── this generates a value for every case
   │ 
   │ Help: Keep one of them, or write two tests — one over the rows and one over the generated values.
   │ 
   │ Note: A table test runs its body once per row a reader wrote; a property test runs it once per value the runner made up. One body can not do both.
───╯

Keep one of them, or write two tests.

Taught on: Tests › Table tests

snapshot-in-property

Error. A property test records a snapshot. It runs once per generated value, so the snapshot would record a different value each time.

[snapshot-in-property]
Error: A property test can not record a snapshot
   ╭─┤ Double.es:9:25 │
   │
 9 │        expect double(number) matches snapshot from "doubled"
   │                              ───────────────┬───────────────  
   │                                             ╰───────────────── every case would record here
   │ 
   │ Help: Assert what holds for every value instead — 'expect …' — and snapshot a value a test WROTE, in a test of its own.
   │ 
   │ Note: A property test runs its body once per generated value, so a snapshot written here records a different value every case and only the last of them could ever match.
───╯

Assert what holds for every value, and snapshot fixed values in a test of their own.

Taught on: Tests › Property tests

value-comment-outside-tests

Warning. A §? value comment is written outside the tests { … } block, where nothing records the value.

[value-comment-outside-tests]
Warning: This value comment is answered by nothing
   ╭─┤ Rate.es:2:38 │
   │
 2 │     constant rate = 3::multiply(with 2) §?
   │                                         ─┐  
   │                                          ╰── no test records the value of this line
   │ 
   │ Help: Ask it of a Statement inside the 'tests { … }' block, or write '§' for a Comment that asks nothing.
   │ 
   │ Note: A '§?' asks for the value of the Statement it ends, and the points that record one are handed out while a 'tests { … }' block is compiled. Everywhere else it is an ordinary Comment.
───╯

Ask it of a statement in the tests { … } block, or write § for a plain comment.

Quick Fix: Write an ordinary ‘§’ Comment.

Taught on: Tests › Examples and value comments

Asynchrony

The two words work is written with, and the two ways a value that is work goes missing. Asynchrony teaches all five.

complete-outside-future

Error. complete stands where nothing can wait for it. A body that writes complete suspends, so it hands its caller a future and has to declare -> Future<…>. The report has two shapes: a named function or method whose declared return type is not a Future, and a position that can not suspend at all.

[complete-outside-future]
Error: 'complete' waits, and nothing here can wait
   ╭─┤ Headline.es:3:23 │
   │
 3 │        constant answered = complete Async.deferred(() { <- url })
   │                            ───────────────────┬──────────────────  
   │                                               ╰──────────────────── this Function returns String
   │ 
   │ Help: Declare the return Type 'Future<String>'.
   │ 
   │ Note: A body that writes 'complete' suspends, so it hands back a Future the caller completes in its turn — which is what its declared Type has to say.
───╯

Declare the return type a future of what the body answers with. The positions that can not suspend are a parameter’s default, a test’s name, a benchmark body and a property body, test … for any (…); each reports the same code, under one label that says the position can not suspend, and the Note names all four. There the fix is to complete the work above the position, into a constant it reads.

Where the value after complete is no work at all, as in <- complete x with x an Integer, the word itself is the mistake. The help is then Drop the 'complete'., in either shape, and needless-complete is not reported as well.

Quick Fix: Declare the return Type ‘Future<String>’, wrapping the return type the body already declares. It is offered on a complete in a body, and not in a parameter’s default, where wrapping that function’s return type would leave the default exactly as wrong. Before a value that is no work, the Quick Fix is Drop the ‘complete’ instead, wherever the word stands.

Taught on: Asynchrony › A body that waits

unused-future

Error. A statement is a future. Building one runs nothing, so a description nobody starts and nobody waits for does nothing at all.

[unused-future]
Error: Nothing here runs
   ╭─┤ Report.es:8:2 │
   │
 8 │     delayed("a")
   │     ──────┬─────  
   │           ╰─────── this is a Future<String>, and its value goes nowhere
   │ 
   │ Help 1: Did you mean 'complete', to wait for it — or 'start', to put it in flight and carry on?
   │ Help 2: Or, where the call was written for what it does rather than for what it answers, hold its answer in a Constant.
   │ 
   │ Note: A Future describes work. Building one runs none of it — 'start' puts it in flight and 'complete' waits for what it answers with.
───╯

Write complete in front of it to wait for it, or start to put it in flight and carry on.

Where the statement is a call written for what it does — Terminal.inspect(work) prints, and answers with what it was handed — neither keyword is the edit. Hold the answer in a constant.

Quick Fix: Wait for it with ‘complete’ and Put it in flight with ‘start’. Neither is preferred over the other: both are whole things to mean, and the line does not say which.

Taught on: Asynchrony › One run, read many times

unobserved-started

Information. A statement is a started run. It does run — what nobody does is read what it answers with. Fire and forget is allowed, and this says so once.

[unobserved-started]
Advice: Nothing waits for this
    ╭─┤ AsynchronyStatements.es:27:2 │
    │
 27 │     start headline()
    │     ────────┬───────  
    │             ╰───────── this runs, and nobody reads its answer
    │ 
    │ Help: Hold it in a Constant and 'complete' it where the answer is wanted, if the answer is wanted at all.
    │ 
    │ Note: A Started can be completed any number of times, from anywhere — holding it under a name is what makes that possible later.
────╯

Leave it where the answer is genuinely not wanted. Otherwise hold the run in a constant and complete it where the answer is.

The label says which statement it is. A start reads this runs, and nobody reads its answer; a call that merely answered with a run reads this answers a run, and nobody reads what it answers with.

Inside a test body, fire and forget lasts as long as the test does: a test runs under a context of its own, and stopping a run stops everything it started, so work the test walked away from is stopped when the test ends. It can not print into the next test’s report, and it can not hold essence test open.

There is no Quick Fix. Both answers are things only you know: leaving it is no edit at all, and holding it in a constant needs a name for the work.

Taught on: Asynchrony › One run, read many times

needless-complete

Warning. The value after complete is neither a Future nor a Started, so it is already the answer. The span is greyed out rather than underlined.

[needless-complete]
Warning: This is not work to wait for
   ╭─┤ Waited.es:2:20 │
   │
 2 │     constant waited = complete 3
   │                                ▲  
   │                                ╰── this is an Integer
   │ 
   │ Help: Drop the 'complete'.
   │ 
   │ Note: 'complete' waits for what a Future or a Started answers with — a value that is neither is already the answer.
───╯

Drop the word. Where the complete also stands where nothing can wait, the one report is complete-outside-future, with the same help.

Quick Fix: Drop the ‘complete’.

Taught on: Asynchrony › A body that waits

needless-start

Warning. The value after start is not a Future, so it describes no work to put in flight.

[needless-start]
Warning: This is not a Future, so there is nothing to start
   ╭─┤ Running.es:2:21 │
   │
 2 │     constant running = start 4
   │                              ▲  
   │                              ╰── this is an Integer
   │ 
   │ Help: Drop the 'start'.
   │ 
   │ Note: 'start' puts a Future in flight and answers the one run of it — a value that is not a Future describes no work to run.
───╯

Drop the word. A Started reports the same code with a message of its own, This is already in flight, and a note of its own — A Started is one run of a Future, and it belongs to whoever started it — there is no second run to ask for. The note above it is about a value that is not work, which is the opposite complaint, so the two are not shared.

Quick Fix: Drop the ‘start’.

Taught on: Asynchrony › One run, read many times

The project file

Mistakes in essence.json. Each is a Warning: the setting falls back to its default and the run goes on. essence build, run, watch, test and init report them at the head of a run; essence check does not.

unknown-setting

Warning. essence.json has a key that is not a setting. The Note lists the settings at that level. Nothing is read from the key.

[unknown-setting]
Warning: "exclusions" is not a setting
   ╭─┤ essence.json:2:2 │
   │
 2 │     "exclusions": ["build"]
   │     ──────┬─────  
   │           ╰─────── not a setting
   │ 
   │ Help: Remove the key, or write one of the settings above.
   │ 
   │ Note 1: The settings at the top of essence.json are "$schema", "exclude", "test", "build".
   │ Note 2: Nothing was read from this key.
───╯

"exclusions" is three edits from "exclude", which is past the near-miss rule — so the help is the one edit that always holds. A key that IS a near miss is answered Did you mean "exclude"? instead, with a quick fix behind it; and a key that spells a PATH is a setting written flat, which is nested rather than renamed: "test.cases": 200 is answered Write it nested: "test": { "cases": 200 }.

Quick Fix: Change to “exclude” when the key is a near miss, or Nest it when the key spells a path.

Taught on: essence.json › Mistakes are Warnings

setting-shape

Warning. A setting has a value of the wrong shape, such as a string where a list of tags belongs.

[setting-shape]
Warning: "test.skipTags" is not a list of tag names
   ╭─┤ essence.json:3:15 │
   │
 3 │        "skipTags": "slow"
   │                    ───┬──  
   │                       ╰──── written as a String
   │ 
   │ Help: Write it as a list of tag names: ["slow"]
   │ 
   │ Note: No tag is skipped by default.
───╯

Write the shape the help shows. The value in it is the one that was WRITTEN, read as the value it means: "skipTags": "wip" is answered ["wip"], "minify": "false" is answered false, and "cases": "50" is answered 50. Where the written value says nothing about what was meant — "cases": "many" — the catalogue’s own value is offered as an example instead: Write it as a whole number of at least 1 — '200', say.

Quick Fix: Write it as …, wherever the value coerces — the same computation the help prints, so the two never disagree about a number.

Taught on: essence.json › Mistakes are Warnings

moved-setting

Warning. A key is written where its setting used to be read. test.exclude is now the top-level exclude.

[moved-setting]
Warning: "test.exclude" has moved to "exclude"
   ╭─┤ essence.json:3:3 │
   │
 3 │        "exclude": ["fixtures"]
   │        ────┬────  
   │            ╰────── no longer read here
   │ 
   │ Help: Move it: "exclude": ["fixtures"]
   │ 
   │ Note 1: "exclude" keeps the editor out of those directories as well as the test walk, so it sits at the top rather than under "test".
   │ Note 2: Nothing was read from this key.
───╯

Move it to the top of the file: "exclude": ["fixtures"].

Quick Fix: Move it to “exclude”.

Taught on: essence.json › Mistakes are Warnings

unreadable-project-file

Warning. essence.json does not parse. It is JSON with comments and trailing commas allowed. Every setting stays at its default until the file parses.

[unreadable-project-file]
Warning: essence.json could not be read as JSON
   ╭─┤ essence.json:2:1 │
   │
 2 │     "exclude": ["build"
   │ ▲───  
   │ ╰───── a ']' was expected here
   │ 
   │ Help: Write the ']' that closes the list.
   │ 
   │ Note 1: Every setting is at its default until the file reads.
   │ Note 2: The file is JSON with comments and trailing commas allowed, as tsconfig.json is.
───╯

Write what the label says was expected. The help names that token where the parser names one — a }, a ], a :, a ,, a quoted key, a value, the */ of a comment — and is absent for the verdicts that say a character cannot stand where it does rather than that one is missing. It is offered for the first refusal alone: the parser recovers generously, and what it asks for after that is about text it has already lost track of.

The parser asks for a , wherever a list or an object goes on unclosed. Where that , would stand in front of a closer of the other kind, or of a key inside a list, writing it would not read, so the help names the bracket that was left open instead: Write the ']' that closes the list. A ] where no list is open is the object’s } mistyped, and the help says to write } in its place.

Taught on: essence.json › Mistakes are Warnings

The compiler as a program

Problems with the run itself rather than with a program. These reports have no source location.

file-not-found

Error. A file named on the command line does not exist.

[file-not-found]
Error: No such file: src/Mian.es

Help: Did you mean 'src/Main.es'?

Check the path. A near miss against the .es files beside the path is answered; where there is none, the Help asks for the path and where the file is saved.

Two things differ by command, and neither is a mistake. essence check and essence build print the path as it was typed, while essence test prints the absolute one it resolved. And a directory named where a file belongs is refused by check and build — see not-a-file — while essence test src reads it as a directory to scan and prints no tests in src, exiting 0.

Taught on: Running tests

not-a-file

Error. A directory is named where a source file belongs.

[not-a-file]
Error: src is a directory

Help: Pass the source files inside it instead — 'src/*.es'.

Name the files inside it, for example src/*.es.

Taught on: Command line › The shape of an invocation

unreadable-file

Error. The file exists but cannot be read, usually because of its permissions.

[unreadable-file]
Error: Not allowed to read Locked.es

Help: Check the file's permissions.

Fix the file’s permissions.

essence format --check does not go through the diagnostic system at all: a file it cannot read is reported as Missing.es: could not be read., with no code and no Help.

bundle-failed

Error. The generated JavaScript could not be bundled. The message starts with Could not bundle the generated JavaScript:. This is a compiler bug.

Report it, with the program that caused it.

bundler-warning

Warning. The JavaScript bundler reported a warning. The compiler passes it through unchanged.

Read the bundler’s message. Your program still builds.

Everything else

An @ written where it names nothing, a standard-library declaration, and a failure inside the compiler.

at-outside-method

Error. @ is used outside a method or a match arm, where it names nothing.

[at-outside-method]
Error: There is no '@' here to refer to
   ╭─┤ Me.es:2:16 │
   │
 2 │     constant me = @
   │                   ▲  
   │                   ╰── this is outside any Method or Handler
   │ 
   │ Note: '@' is the receiver of a Method or the value a Match Handler matched.
───╯

Use @ inside a method, for its receiver, or inside a match arm, for the matched value.

Taught on: Namespaces and methods › The receiver, @

at-in-static-method

Error. @ is used in a static method, which has no receiver.

[at-in-static-method]
Error: There is no '@' in a static Method
   ╭─┤ Point.es:6:7 │
   │
 6 │          <- @
   │             ▲  
   │             ╰── this Method is called on the Namespace
   │ 
   │ Help: Take the value as a Parameter, or drop 'static' to make this an instance Method — then every call writes its receiver, 'value::name(…)' rather than 'Namespace.name(…)'.
   │ 
   │ Note: '@' is the receiver of an instance Method, and a static Method is called without one.
───╯

Take the value as a parameter, or return a value built in the body: static origin() -> Point { <- { x = 0, y = 0 } }. Remove static instead when the method is meant to run on a value.

Quick Fix: Drop ‘static’ — never applied on its own, because it changes how the method is called. Every existing Namespace.name(…) becomes argument-count-mismatch until it is rewritten as value::name(…), and the note on each one names a parameter you never wrote.

Taught on: Namespaces and methods › The receiver, @

native-property-without-type

Error. A static property in a declarations { … } file has neither a value nor a type. Only the standard library’s own sources can hit this, because a program cannot open a declarations block (see declarations-outside-stdlib).

Annotate the property with its type, as in static Pi: Transcendental.

internal-error

Error. The compiler failed where it should have reported a problem. Apart from the install problem below, this is a compiler bug.

Report it, with the program that caused it. The one known cause outside the compiler is Yarn’s Plug’n’Play install, under which essence build stops with this error. Switch the project to a node_modules folder.

Taught on: Installation › Add it to a project

esc