-
Dropped support for GHC 8.8, 8.10, and 9.0.
-
Agda supports GHC versions 9.2.8 to 9.14.1.
-
New option
--parallel(-jfor short, as inmake) lets Agda type-check imported modules in parallel. For large libraries, this can result in a speedup of ~3x, at the cost of roughly doubling the maximum memory usage. -
New option
--print-optionsto print a simple list of all options. This list can e.g. be used to implement bash completion. -
The flavor of Cubical Agda can now be chosen by an argument to the
--cubicaloption:Old New --cubical--cubical, or--cubical=full--erased-cubical--erased-cubical, or--cubical=erased--cubical-compatible--cubical-compatible, or--cubical=compatible- --cubical=no-glueFor compatibility between modules using different variants of Cubical Agda, see the documentation.
-
New flag
--no-write-interfaces. -
New command-line option
--literate-markdown-only-agda-blocks(off by default). When enabled, only code blocks explicitly marked with```agdaare treated as Agda code in literate Markdown (.lagda.md) and Typst (.lagda.typ) files. Unmarked code blocks (```) are treated as verbatim text and not type-checked. This option must be set via command line since it affects parsing. (See #7971.) -
The flag
--termination-depth=Nnow means maximum termination depth and the termination checker now performs iterative deepening, starting with depth1and increasing it up to the givenN, stopping early as soon as the termination check succeeds. IncreasingNcan thus slow down things only for failing termination checks.The default value of
Nhas been increased from1to3, yet not higher, because cases requiring a termination depth> 1are already very rare in practice.There is also an internal change to the termination checker. Dot patterns are now taken into account from the beginning and not only when the termination check fails without taking them into account. The overhead to also mine dot patterns for structural descent was already negligible so it made sense to simplify the termination checking algorithm.
-
The new flag
--no-occurrence-analysiscan be used to turn off the automated occurrence analysis for functions.By default Agda analyses how functions use their arguments. For instance, Agda can tell that
Din the following code is strictly positive, becauseVecuses itsSetargument in a strictly positive way:open import Agda.Builtin.Nat open import Agda.Builtin.Unit data _×_ (A B : Set) : Set where _,_ : A → B → A × B Vec : Set → Nat → Set Vec A zero = ⊤ Vec A (suc n) = A × Vec A n data D : Set where c : ∀ n → Vec D n → D
However, this analysis can be slow, especially for big mutual blocks. Now it is possible to turn it off.
The analysis is also used to detect unused function arguments. The following code is by default accepted, but it is rejected if the occurrence analysis is turned off:
open import Agda.Builtin.Bool open import Agda.Builtin.Equality open import Agda.Builtin.Unit F : Bool → Set → Set F true _ = Bool F false _ = ⊤ _ : {b : Bool} → F b Bool ≡ F b ⊤ _ = refl
Note that an alternative to the analysis is to use polarities. The following code is accepted:
{-# OPTIONS --polarity --no-occurrence-analysis #-} open import Agda.Builtin.Bool open import Agda.Builtin.Equality open import Agda.Builtin.Nat open import Agda.Builtin.Unit data _×_ (@++ A B : Set) : Set where _,_ : A → B → A × B Vec : @++ Set → Nat → Set Vec A zero = ⊤ Vec A (suc n) = A × Vec A n data D : Set where c : ∀ n → Vec D n → D F : Bool → @unused Set → Set F true _ = Bool F false _ = ⊤ _ : {b : Bool} → F b Bool ≡ F b ⊤ _ = refl
-
Setting environment variable
NO_COLORnow turns off coloring in the default--color=automode. It can be overwritten by--color=always. See also https://no-color.org/ . -
New option
--quote-metasto allow forquoteTermconstraints to be solved even when the quoted term contains unsolved metas. This allows for elaborating macro applications with quoted arguments that still have interactive holes in them. See the quote metas documentation. -
{-# NO_POSITIVITY_CHECK #-}pragmas are now recognized inrecorddeclarations andwhereblocks, and pertain to the followingdataorrecorddeclaration or mutual block. -
New option
--local-rewritingwhich enables parameterising over computation rules by annotating module parameters with@rewriteattributes. See the local rewriting documentation for more info. -
New
primRewriteNoMatchprimitive inAgda.Builtin.Equality.Rewritefor controlling rewrite rule matching. See the section in the rewriting documentation for more info. -
The
ETApragma has been removed. -
Eta-equality for record types is no longer inferred. Previously Agda would switch off eta for a recursive record type automatically if there was a risk that the type checker could loop due to infinite eta expansion. Now, Agda will only flag it with an
UnguardedEtaRecorderror, so one has to add ano-eta-equalitydirective manually. If one wants eta enabled nevertheless, one can use the newETA_EQUALITYpragma. This pragma replaces the oldETApragma and can also be used to turn on eta forcoinductiverecord types. See the documentation on unguarded records and theETA_EQUALITYpragma. -
New options
--irrelevance(default on) and--no-irrelevanceto allow or disallow the irrelevance modality.
-
Error
ClashingDefinitionnow gives the lineage of the previous definition of the same name. This helps when it is unclear how this name was imported. Example:error: [ClashingDefinition] Multiple definitions of A. Previous definition A is in scope as * a postulate Imports.A.A brought into scope by - the opening of Imports.A at ... - its definition at ... -
Errors
GenericErrorandGenericDocErrorhave been replaced by more specific errors. (Issue #7225.) -
Generalisation failures due to unresolvable dependencies between a generalized variable and unsolved metavariables have new, specific errors.
-
New warning
UnusedImportswhenopenbrings identifiers into scope that are definitely not used subsequently.If
usingorrenamingdirectives are given, or in flavor-WUnusedImports=all, Agda warns about each name that is unused. If no directive or only ahidingdirective is given, and unless the flavor isall, Agda only warns if none of the imported names are used.Agda also warns about instances brought into scope unless
--no-qualified-instancesis on (which requires bringing instances into scope if they should be found by instance search). -
UselessImportwarning instead of parse error when an module is instantiated but not opened duringimport, for instance:import Structures.IsMonoid Carrier Eq
This does not bring module
Structures.IsMonoidinto scope and neither any of its exports. It either needs anopenor anas-clause such asas MyMonoid. -
UselessPragmawarning instead of hard errorNeedOptionRewritingwhen aREWRITEorBUILTIN REWRITEpragma is encountered but--rewritingis off. -
Error warning
IllegalDeclarationInDataDefinitioninstead of hard error whendatadefinition contains declarations other than type signatures of constructors. -
Error
RecursiveRecordNeedsInductivityturned into a error warning. -
New warning
DivergentModalityInClausewhen modality of a clause diverges from that of the function. Example:A : Set₁ @0 A = Set
-
New warning
InvalidDataOrRecDefParameterfor information (e.g. type, attributes) attached to parameters in adataorrecorddefinition (that is separate of its data or record signature). This replaces errors:UnexpectedModalityAnnotationInParameterUnexpectedTypeSignatureForParameter
-
New warning
InvalidTacticAttributefor misplaced@(tactic ...)attributes. This was silently accepted up to Agda 2.8.0 but raises now the new warning:postulate @(tactic not-in-scope) _ : Set
-
New warning
RewriteVariablesBoundInSingletonfor rewrite rules which bind at least one variable exclusively in patterns which might become of singleton type after a substitution. Rewrite rules of this form endanger subject reduction.- Unlike the other warnings about problematic rewrite rules, Agda will still try its best to apply rewrites which trigger this warning. This is because some very useful rewrite rules unfortunately do not preserve subject reduction in the presence of definitional singletons.
-
UnknownNamesInFixityDeclandUnknownNamesInPolarityPragmasare now error warnings. -
The new warning
DefinitionBeforeDeclarationis emitted if in a classicmutualblock a data/record signature appears after the respective definition. This can happen since the nicifier bubbles signatures up. (See issue #8435.) -
New warning
ShouldBeEtaRecordPattern, raised for matches on record constructors in binders (λ,let, parameter telescopes etc.) when the respective record does not have eta. For example, this module parameter match triggers the warning:record Wrap (A : Set) : Set where constructor wrap; no-eta-equality; pattern field unwrap : A module _ {A} (w@(wrap a) : Wrap A) where
Reason for the warning: Such a binding is interpreted here as
a = unwrap w. The user expectation thatwis definitionally equal towrap ais only met ifWrapadmitseta-equality.Pattern matching on left hand sides of function definitions does not trigger the warning.
Changes to the Agda syntax.
-
Breaking: The parser will reject ASCII opening delimiters which are closed by a Unicode delimiter, and vice-versa. Concretely, this means the mismatched pairs
⦃ ... }}/{{ ... ⦄and⦇ … |)/(| … ⦈are now parse errors. -
Records can now be created using module-like syntax in place of curly braces and semicolons.
p : Pair Nat Nat p = record where fst = 2 snd = 3
See #4275 for the proposal.
-
Modality annotations in aliases and let-bindings are now supported (PR #7990). Example:
split : {A B C : Set} (@0 p : A × B) (k : @0 A → @0 B → C) → C split p k = let @0 (x , y) = q in k x y where @0 q = p
-
Postfix projections cannot be surrounded by parentheses anymore. E.g. these postfix projection applications are now illegal in expressions:
r (.proj) r .(proj)
-
Idiom brackets and
donotation may now appear qualified, as inM.doorM.(| f x y z |), in which case the functions needed for desugaring these are looked up inMrather than in the surrounding scope.
Changes to type checker and other components defining the Agda language.
-
(BREAKING): In the presence of
--erasure, types of lambdas expressions are not inferred unless every lambda-bound variable has been given its erasure status (@0or@ω) explicitely. The reason is that otherwise Agda might infer the wrong erasure status, see, e.g., Issue #7001.Now we have the following behavior:
fails = λ x → x + x succeeds = λ (@ω x) → x + x alsoOK = λ (@ω A : Set) (@0 B : Set) → A
With that change
--erasuregets more akin to Cubical Agda that categorically refuses to infer lambdas (since they could construct either functions or paths). -
(BREAKING): Instance search will no longer eta-expand non-instance (visible and hidden) variables of record type in the context to find instance fields (PR #8367).
This change means that instance search can now happen even when the types of non-instance arguments are yet-unsolved metavariables. Specifically, instance search now works in functions with a type signature of the form
∀ x → ..., where previously it would require the type ofxto be annotated.It also means that instance search no longer requires head-normalising the types of non-instance function arguments, which may have a positive effect on type checking performance.
Due to this change, code that relied on eta-expanding visible argument (like
r : Rin the example below) to find the instance field will no longer work.postulate T : Set use : ⦃ t : T ⦄ → Set record R : Set where field ⦃ inst ⦄ : T fails : R → Set fails r = use
In this case the code can be repaired by explicitly eta-expanding the record pattern:
succeeds : R → Set succeeds r@record{} = use -- or just record{}, if r is unused
In other cases more substantial changes might be required. For example, in the code below the record values
AaandBbare parameters so they cannot be eta-expanded directly:record IsPointed (A : Set) : Set where field point : A open IsPointed {{...}} record PointedSet : Set1 where field Carrier : Set {{IsPointed[Carrier]}} : IsPointed Carrier open PointedSet record PointedFunction (Aa Bb : PointedSet) : Set where field run : Aa .Carrier -> Bb .Carrier preserves-point : run point ≡ point
Here it is possible to work around the problem by marking the projection
IsPointed[Carrier]as aninstanceand then applying the record modulePointedSetto the respective valuesAaandBb:record PointedSet : Set1 where field Carrier : Set instance {{IsPointed[Carrier]}} : IsPointed Carrier open PointedSet record PointedFunction (Aa Bb : PointedSet) : Set where open PointedSet Aa renaming (Carrier to AA) open PointedSet Bb renaming (Carrier to BB) field run : AA -> BB preserves-point : run point ≡ point
In general, instance search is intended to work well with unbundled structures such as
IsPointed, while using it with bundled structures such asPointedSetmight require some more creative workarounds such as the one above. -
Instance search now finds instance fields in functions that produce eta records (Issue #8337), as long as these functions are in the context with instance visibility.
In effect, this means that a family of instances of a "subclass" also provides a family of instances for the "superclass". For example, the following code is now accepted:
record Eq (A : Set) : Set where field _==_ : A → A → Bool record Ord (A : Set) : Set where field ⦃ eq ⦄ : Eq A _<=_ : A → A → Bool open Ord ⦃ ... ⦄ open Eq ⦃ ... ⦄ test : {I : Set} {F : I → Set} ⦃ ordi : ∀ {i} → Ord (F i) ⦄ → (i : I) → F i → F i → Bool test i x y = x == y
-
Functions defined using with-abstraction equality (
with … in eq) can now be reasoned about using the same with-abstraction equality: the equality proof is correctly generalised over. This should make most (if not all) uses of the old-styleinspectidioms for the built-in equality type unnecessary. -
Added support for Cubical Agda without Glue Types by using the flag
--cubical=no-glue, a variant of Cubical Agda which disables the Glue types. For compatibility with modules using--cubical[=full]and--cubical=erased, see variants. -
Added the Sharp modality, which adds a right adjoint to the existing flat modality enabled via the
--cohesionflag. This also enables the use of attributes in record fields for any cohesion modality which has a left adjoint (currently just sharp and continuous).
-
tcTypeErrornow throwsUserErrorinstead ofGenericDocError. -
Tactic arguments (
@tactic) are now supported in module telescopes.
- Suppport for version-specific
defaultsfiles: a file whose name is of the formdefaults-X.Y.Zwill take precedence over the standarddefaultsone for theX.Y.Zversion of the compiler. This can be used to have default libraries that are only compatible with a given version of the compiler.
-
Syntax highlighting and go-to-definition now also works in the Agda information and debug buffers in Emacs where goals etc. are displayed. This fixes long-standing Issue #706.
-
By temporarily turning on printing of hidden arguments (
OPTION --show-implicit,C-c C-x C-hin Emacs) and then splitting on result in a hole (C-c C-c RETin Emacs, the whole sequence beingC-c C-x C-h C-c C-c RET), hidden arguments can be introduced in the left hand side of a clause. In the presence of generalized variables, this used to introduce unparsable names. For instance:variable l : Level A : Set l id : A → A id = {!!}
Here,
id {A.l} {A} x = ?was produced, triggering an error. Now, the correctid {A = A} x = ?is produced (Issue #8153). -
Catch-all copattern clauses are now tolerated as unreachable clauses rather than being outright rejected with a
CosplitCatchallerror. They can be used as jumpboard for further result splitting. (A scenario is a record type that got extended with new fields, and definitions producing record values need to be extended as well.) Example:test : Σ A B test .fst = a test = {!!} -- C-c C-c RET
This split produces the clause
test .snd = ?. (Issue #8139). -
A normalization level can now also passed to command
Cmd_constraints("show constraints",C-c C-=in Emacs). In Emacs, the normalization level is given as usual byC-uprefixes.This interface change is breaking for frontends to
agda --interactionsuch as the VSCodeagda-mode, which need updating. -
Fixed an internal error in
Cmd_helper_function(C-c C-hin Emacs) (Issue #8103). Changed the type ofGoal_HelperFunctionwhich might be breaking 3rd-party interaction frontends. -
NON_TERMINATINGfunctions now only reduce inIgnoreAbstractmode of commandsCmd_compute(_toplevel)(C-u C-c C-nin Emacs) regardless of whether invoked at toplevel or in a hole (Issue #2410). -
Go-to-definition (
M-.) is now implemented using Emacs' built-in Xref. Basic usage stays the same (M-.or using the mouse), but now also includes searching for definitions by exact (C-u M-.) or approximate names (C-M-.) and listing references (M-?) in loaded files.
-
agda --html --html-highlight=code example.lagda.treenow produceshtml/example.tree, which Forester can consume directly; no external tools needed. -
New option
--ghc-tracefor GHC Backend to instrument code such that the Agda name of the function is printed tostderrwhenever a function is entered. -
The JS backend now explicitly lists all primitives that should compile to
undefined. Primitives not in this list or the RTS trigger a newUnknownJSPrimitivewarning (see #8352). -
The JS backend's CJS & AMD module styles are now deprecated. Please use ES6 module style instead (
--js-es6).
For 2.9.0, the following issues were closed (see bug tracker):