Agda
Safe HaskellNone
LanguageHaskell2010

Agda.TypeChecking.Conversion.Errors

Description

Implementation of conversion checking errors which can reify part of the context leading to the actual failure as terms.

Synopsis

Public interface

Conversion checking errors are initially thrown (by failConversion) in the floating state, which means they can accumulate information on where they happened as the call stack unwinds. This information will be presented to the user by wrapping the actual mismatched terms in a skeleton of the term where the mismatch happened. These terms had better not be nonsense! This requires that recursive calls within the conversion checker cooperate with the reconstruction process, using the functions in this module. Their use can be summarised as follows:

  • A recursive call to compare a subterm of a normal form should be guarded by addConversionContext.
  • A recursive call to a domain-specific conversion checking function which takes the input terms apart using a nontrivial view (e.g., equalLevel) should be guarded by nowConversionChecking.
  • A recursive call under an application of a nontrivial substitution to the context and terms under consideration should be guarded by cutConversionErrors.
  • Recursive calls that preserve the definitional identities of the terms under consideration do not need any special handling.

The goal of these rules is to allow for the user to pretend that conversion checking works by normalising then checking for syntactic equality: the reconstructed term should wrap the actual mismatch in "hereditary neutrals (to the left)", i.e. everything that compared equal on the way to the mismatched terms is normalised, but parts of the term that are beyond the mismatch are left as-is (and, in the future, will be presented "deemphasized").

How much of the context to reify is a design parameter that can be tuned. At the moment, we drop all ConvLam, ConvDom, ConvCod and visible ConvApply from the front of the zipper. Regardless, the conversion checker must be set up as if the entire context will be reified.

failConversion Source #

Arguments

:: (MonadTCError m, HasBuiltins m) 
=> Comparison

Equality or subtyping?

-> Term

See convErrLhs

-> Term

See convErrRhs

-> CompareAs

Will be converted to a FailedCompareAs.

-> m a 

Throw a floating ConversionError, given the arguments of compareAs.

mismatchedProjections Source #

Arguments

:: (MonadError TCErr m, PureTCM m) 
=> Type

LHS type, t1

-> Term

LHS term, v1; see convErrLhs.

-> Elims

Additional eliminations e1 present on the LHS beyond the failure of conversion checking

-> Type

RHS type, t2

-> Term

RHS term, v2; see convErrRhs.

-> Elims

Additional eliminations e2 present on the RHS beyond the failure of conversion checking

-> m a 

mismatchedProjections t1 v1 e1 t2 v2 e2 raises a floating conversion-checking error (as per failConversion) indicating that the terms v1 and v2 (which have type t1 and t2 respectively, and are typically neutral) disagree on the last elimination in their spines.

The further eliminations e1 and e2 are treated as "uncompared" context for the error message.

addConversionContext Source #

Arguments

:: MonadTCError m 
=> (ConversionZipper -> ConversionZipper)

How to modify the zipper

-> m a

Generally, a recursive call to the conversion checker

-> m a 

Add some call stack context to floating ConversionErrors thrown from the continuation.

This function should be placed on the outside of addContext, and the changes to the context should be reflected in the ConversionZipper.

Unreifiable recursive calls

The ConversionZipper reflects recursive calls made to conversion checking of the immediate subterms of a normal form, and it can handle most cases of a recursive call happening in a weakening of the current context as well. However, some conversion-checking functions take the input values apart in nontrivial, type-specific ways before eventually calling into "ordinary" term conversion checking again.

If a floating ConversionError happens in one of these eventual calls, the reified call stack will not have anything corresponding to the value that got taken apart; this can result in the terms presented to the user being ill-typed (see testFailConvErrCtxLevels for an example). These calls can be handled in two ways, depending on whether or not preserving the surrounding context is likely to be useful in an error message. Here are examples of using each:

  • Calls to equalLevel are likely to happen while checking hidden arguments to a defined symbol (e.g. a universe-polymorphic data type), which is a context worth preserving for error messages: telling the user l != l' is significantly less useful than telling them List {l} A != List {l'} B.

    Therefore, the call to equalLevel in equalTerm' is guarded by nowConversionChecking. If an error happens while conversion-checking some levels, the mismatched terms will be replaced by the (normalised forms of) the entire levels that were being compared.

  • On the other hand, conversion checking of partial elements involves nontrivial modifications to the context, and, more importantly, generally happens to terms which display quite terribly before these substitutions are applied, often involving eta-expanded extended lambdas and the primitive primPOr. Subjectively, it's less useful to say that conversion checking failed for the hard-to-read system than it is to say that it failed for a particular face.

    For these reasons, compareTermOnFace (really, forallFaceMaps) uses cutConversionErrors to turn any floating errors from conversion-checking the faces into Finished errors, which no longer accumulate context. Whatever context was collected inside the face comparison will be preserved, but we will not remember that (or where) the partial elements were being compared.

nowConversionChecking Source #

Arguments

:: (MonadTCError m, HasBuiltins m) 
=> Comparison

Equality or subtyping?

-> Term

See convErrLhs

-> Term

See convErrRhs

-> CompareAs

Will be converted to a FailedCompareAs.

-> m a

Generally, a recursive call to a type-specific conversion checking function.

-> m a 

Replaces any floating ConversionErrors raised by the continuation with the one generated (as per failConversion) from the given arguments.

cutConversionErrors :: (MonadPretty m, MonadError TCErr m) => m a -> m a Source #

Freeze ConversionErrors thrown by the continuation.

This function should be placed on the inside of context updates.

Types

data ConversionError Source #

A conversion checking failure.

A conversion checking error can be in two states (according to its convErrCtx): it is either Finished or Floating.

A Finished conversion-checking error packages a pair of unequal terms, which are well-typed in the context that the error was raised in, with sufficient information for printing an informative error message. Finished errors will not accumulate further call stack information.

A Floating conversion-checking error is subject to be modified as the conversion checker's call stack unwinds, by appending to its ConversionZipper. Some frames in a ConversionZipper alter the context in which the terms convErrLhs and convErrRhs should be interpreted. Floating errors can be re-raised as Finished errors using cutConversionErrors. This means that any code which catches those errors will have types valid directly in the TypeError closure, but no more context will be accumulated for them.

Constructors

ConversionError 

Fields

Instances

Instances details
PrettyTCM ConversionError Source # 
Instance details

Defined in Agda.TypeChecking.Conversion.Errors

NFData ConversionError Source # 
Instance details

Defined in Agda.TypeChecking.Conversion.Errors

Methods

rnf :: ConversionError -> () #

Generic ConversionError Source # 
Instance details

Defined in Agda.TypeChecking.Conversion.Errors

Associated Types

type Rep ConversionError 
Instance details

Defined in Agda.TypeChecking.Conversion.Errors

Show ConversionError Source # 
Instance details

Defined in Agda.TypeChecking.Conversion.Errors

type Rep ConversionError Source # 
Instance details

Defined in Agda.TypeChecking.Conversion.Errors

data ConversionZipper Source #

A "zipper-like" representation of the edges between comparing a normal form and comparing one of its immediate subterms in the conversion checker's call graph.

Constructors

ConvStop

Thrown at the failing call.

ConvLam

A call to compare the body of a function-typed value.

Fields

ConvDom

A call to compare the domain of a pair of pi types.

Fields

  • (Dom ConversionZipper)

    Information about the domain, and call stack suffix.

  • (Abs Type)

    Codomain of the left-hand side type.

  • (Abs Type)

    Codomain of the right-hand-side type.

ConvCod

A call to compare the codomain of a pair of pi types.

Fields

ConvApply

A call to compare an argument to a function.

Fields

  • Term

    The head term

  • (Abs Type)

    The codomain of the function type at the argument where conversion failed

  • (Arg ConversionZipper)

    Information about the argument, and call stack suffix.

  • [Elim]

    Remaining arguments from the LHS term that conversion checking could not get to.

  • [Elim]

    Remaining arguments from the RHS term that conversion checking could not get to.

Instances

Instances details
PrettyTCM ConversionZipper Source # 
Instance details

Defined in Agda.TypeChecking.Conversion.Errors

NFData ConversionZipper Source # 
Instance details

Defined in Agda.TypeChecking.Conversion.Errors

Methods

rnf :: ConversionZipper -> () #

Generic ConversionZipper Source # 
Instance details

Defined in Agda.TypeChecking.Conversion.Errors

Associated Types

type Rep ConversionZipper 
Instance details

Defined in Agda.TypeChecking.Conversion.Errors

type Rep ConversionZipper = D1 ('MetaData "ConversionZipper" "Agda.TypeChecking.Conversion.Errors" "Agda-2.9.0-inplace" 'False) ((C1 ('MetaCons "ConvStop" 'PrefixI 'False) (U1 :: Type -> Type) :+: C1 ('MetaCons "ConvLam" 'PrefixI 'False) ((S1 ('MetaSel ('Nothing :: Maybe Symbol) 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 (Dom Type)) :*: S1 ('MetaSel ('Nothing :: Maybe Symbol) 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 (Abs ()))) :*: (S1 ('MetaSel ('Nothing :: Maybe Symbol) 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 ArgName) :*: S1 ('MetaSel ('Nothing :: Maybe Symbol) 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 ConversionZipper)))) :+: (C1 ('MetaCons "ConvDom" 'PrefixI 'False) (S1 ('MetaSel ('Nothing :: Maybe Symbol) 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 (Dom ConversionZipper)) :*: (S1 ('MetaSel ('Nothing :: Maybe Symbol) 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 (Abs Type)) :*: S1 ('MetaSel ('Nothing :: Maybe Symbol) 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 (Abs Type)))) :+: (C1 ('MetaCons "ConvCod" 'PrefixI 'False) (S1 ('MetaSel ('Nothing :: Maybe Symbol) 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 (Dom Type)) :*: (S1 ('MetaSel ('Nothing :: Maybe Symbol) 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 ArgName) :*: S1 ('MetaSel ('Nothing :: Maybe Symbol) 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 ConversionZipper))) :+: C1 ('MetaCons "ConvApply" 'PrefixI 'False) ((S1 ('MetaSel ('Nothing :: Maybe Symbol) 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 Term) :*: S1 ('MetaSel ('Nothing :: Maybe Symbol) 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 (Abs Type))) :*: (S1 ('MetaSel ('Nothing :: Maybe Symbol) 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 (Arg ConversionZipper)) :*: (S1 ('MetaSel ('Nothing :: Maybe Symbol) 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 [Elim]) :*: S1 ('MetaSel ('Nothing :: Maybe Symbol) 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 [Elim])))))))
Show ConversionZipper Source # 
Instance details

Defined in Agda.TypeChecking.Conversion.Errors

type Rep ConversionZipper Source # 
Instance details

Defined in Agda.TypeChecking.Conversion.Errors

type Rep ConversionZipper = D1 ('MetaData "ConversionZipper" "Agda.TypeChecking.Conversion.Errors" "Agda-2.9.0-inplace" 'False) ((C1 ('MetaCons "ConvStop" 'PrefixI 'False) (U1 :: Type -> Type) :+: C1 ('MetaCons "ConvLam" 'PrefixI 'False) ((S1 ('MetaSel ('Nothing :: Maybe Symbol) 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 (Dom Type)) :*: S1 ('MetaSel ('Nothing :: Maybe Symbol) 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 (Abs ()))) :*: (S1 ('MetaSel ('Nothing :: Maybe Symbol) 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 ArgName) :*: S1 ('MetaSel ('Nothing :: Maybe Symbol) 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 ConversionZipper)))) :+: (C1 ('MetaCons "ConvDom" 'PrefixI 'False) (S1 ('MetaSel ('Nothing :: Maybe Symbol) 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 (Dom ConversionZipper)) :*: (S1 ('MetaSel ('Nothing :: Maybe Symbol) 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 (Abs Type)) :*: S1 ('MetaSel ('Nothing :: Maybe Symbol) 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 (Abs Type)))) :+: (C1 ('MetaCons "ConvCod" 'PrefixI 'False) (S1 ('MetaSel ('Nothing :: Maybe Symbol) 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 (Dom Type)) :*: (S1 ('MetaSel ('Nothing :: Maybe Symbol) 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 ArgName) :*: S1 ('MetaSel ('Nothing :: Maybe Symbol) 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 ConversionZipper))) :+: C1 ('MetaCons "ConvApply" 'PrefixI 'False) ((S1 ('MetaSel ('Nothing :: Maybe Symbol) 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 Term) :*: S1 ('MetaSel ('Nothing :: Maybe Symbol) 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 (Abs Type))) :*: (S1 ('MetaSel ('Nothing :: Maybe Symbol) 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 (Arg ConversionZipper)) :*: (S1 ('MetaSel ('Nothing :: Maybe Symbol) 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 [Elim]) :*: S1 ('MetaSel ('Nothing :: Maybe Symbol) 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 [Elim])))))))

data ConversionErrorContext Source #

Context for a conversion checking error.

Constructors

Floating ConversionZipper

It still makes sense to collect call stack information for this error.

Finished HereOrThere (Maybe HeadMismatch)

We can not, or do not want to, keep collecting call stack information for this error. Stores "crystallised" information about the actual failing comparison to use as context in error rendering.

data FailedCompareAs Source #

The failing version of CompareAs.

Constructors

FailAsTermsOf Type Type

The conversion checker failed in a typed context.

While the conversion checker is homogeneous (so AsTermsOf only stores a single type), a failing argument comparison early in the spine of a dependent function can cause the reconstructed "context" terms to be heterogeneous.

FailAsTypes

The conversion checker failed in a type-insensitive context.

Instances

Instances details
PrettyTCM FailedCompareAs Source # 
Instance details

Defined in Agda.TypeChecking.Conversion.Errors

NFData FailedCompareAs Source # 
Instance details

Defined in Agda.TypeChecking.Conversion.Errors

Methods

rnf :: FailedCompareAs -> () #

Generic FailedCompareAs Source # 
Instance details

Defined in Agda.TypeChecking.Conversion.Errors

Associated Types

type Rep FailedCompareAs 
Instance details

Defined in Agda.TypeChecking.Conversion.Errors

type Rep FailedCompareAs = D1 ('MetaData "FailedCompareAs" "Agda.TypeChecking.Conversion.Errors" "Agda-2.9.0-inplace" 'False) (C1 ('MetaCons "FailAsTermsOf" 'PrefixI 'False) (S1 ('MetaSel ('Nothing :: Maybe Symbol) 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 Type) :*: S1 ('MetaSel ('Nothing :: Maybe Symbol) 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 Type)) :+: C1 ('MetaCons "FailAsTypes" 'PrefixI 'False) (U1 :: Type -> Type))
Show FailedCompareAs Source # 
Instance details

Defined in Agda.TypeChecking.Conversion.Errors

type Rep FailedCompareAs Source # 
Instance details

Defined in Agda.TypeChecking.Conversion.Errors

type Rep FailedCompareAs = D1 ('MetaData "FailedCompareAs" "Agda.TypeChecking.Conversion.Errors" "Agda-2.9.0-inplace" 'False) (C1 ('MetaCons "FailAsTermsOf" 'PrefixI 'False) (S1 ('MetaSel ('Nothing :: Maybe Symbol) 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 Type) :*: S1 ('MetaSel ('Nothing :: Maybe Symbol) 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 Type)) :+: C1 ('MetaCons "FailAsTypes" 'PrefixI 'False) (U1 :: Type -> Type))