Provide span information in warning/error messages
curry-base!16 (merged) brings support for span information in warning/error messages, which could be adopted here, too. The following list analyzes the currently generated messages in detail and proposes how useful spans could be generated for them:
General
CurryBuilder
Message | Description | Current position | Proposed span | Changes required |
---|---|---|---|---|
errUnknownOptions |
An unknown flag was found in the OPTIONS_FRONTEND pragma. |
A spanInfo2Pos from an OptionsPragma . (CurryBuilder.hs:117) |
The entire OptionsPragma . |
Few |
errIllegalOption |
An illegal option was found in the OPTIONS_FRONTEND pragma. |
See above. | See above. | Few |
Conclusion: In the CurryBuilder it seems to be mainly useful to encompass entire pragma.
Interfaces
Message | Description | Current position | Proposed span | Changes required |
---|---|---|---|---|
errInterfaceNotFound |
An (imported) interface could not be found. | An ImportDecl containing a SpanInfo (Interfaces.hs:83). |
The identifier of the incorrectly imported module in the import declaration. | Few |
errWrongInterface |
Found the wrong interface. | See above. | See above. | Few |
errCyclicImport |
Imports are cyclic. | See above. | See above. | Few |
Conclusion: For errors about imported interfaces, it seems useful to encompass the entire incorrectly imported module's identifier in the import declaration.
Checks
DeriveCheck
Message | Description | Current position | Proposed span | Changes required |
---|---|---|---|---|
errNoAbstractDerive |
Derive requires a constructor on the data type. | The type name identifier in a DataDecl like data C ... (DeriveCheck.hs:35) |
The wrongly derived instance after the derive (like GHC). |
Few |
errNotDerivable |
Typeclass cannot be derived. | The (wrongly) derived instance. | See above. | Few |
errNoDataDerive |
Data cannot be derived |
See above. | See above. | Few |
errNotEnum |
A constructor is non-constant, thus Enum cannot be derived. |
The non-constant constructor. | The constructor. | Few |
errNotBounded |
A constructor has an arity > 1, thus Bounded cannot be derived. |
See above. | See above. | Few |
Conclusion: For errors about derived instances, it seems useful to encompass the derived instance. If a single constructor in the data declaration that causes the issue can be detected, the constructor should be highlighted instead.
ExportCheck
Message | Description | Current position | Proposed span | Changes required |
---|---|---|---|---|
errAmbiguous |
An exported name/type is ambiguous. | The identifier from the export. | The span of the identifier from the export. | Few |
errModuleNotImported |
An exported module is not imported. | See above. | See above. | Few |
errMultiple |
Multiple exports of sth. | The declaration identifier of the first of the multiple exports. | The declaration identifier of the first of the multiple exports.. | Few. |
errNonDataTypeOrTypeClass |
(..) is used after a non-data type. |
The export identifier. | The export identifier. Note that GHC does not emit such an error. | Few |
errOutsideTypeExport |
A record element is exported separately. | See above. | See above. (Note that GHC also does not emit an error here). | Few |
errUndefinedElement |
A non-existent element is exported. | The element's identifier in the export. | The element's identifier in the export. | Few |
errUndefinedMethod |
A non-existent method is exported. | The method's identifier in the export. | The method's identifier in the export. | Few |
errUndefined |
An export is not defined. | The identifier in the export. | The identifier in the export. | Few |
Conclusion: In errors about exported things, it seems useful to encompass the identifier causing the issue in the export declaration. In the case of multiple exports of the same identifier (though possibly different qualifiers), we could encompass the first conflicting identifier and note the spans/positions of all occurrences in the message text.
ExtensionCheck
Message | Description | Current position | Proposed span | Changes required |
---|---|---|---|---|
errUnknownExtension |
An unrecognized language extension is used. | The unknown extension identifier. | The unknown extension identifier. | Few |
Conclusion: In ExtensionCheck errors, it seems useful to encompass the unrecognized extension identifier.
ImportSyntaxCheck
Message | Description | Current position | Proposed span | Changes required |
---|---|---|---|---|
errUndefinedElement |
Importing an unrecognized element from a (known) type. | The unrecognized element's identifier. | The unrecognized element's identifier. | Few |
errUndefinedMethod |
Importing an unrecognized method from a (known) typeclass. | The unrecognized method's identifier. | The unrecognized method's identifier. | Few |
errUndefinedEntity |
Unrecognized import. | The unrecognized import's identifier. | The unrecognized import's identifier. | Few |
errNonDataTypeOrClass |
An alias cannot have elements. | The invalidly imported alias' identifier. | The invalidly imported alias' identifier. | Few |
errImportDataConstr |
A data constructor is imported explicitly. | The invalidly imported constructor identifier in the import. | The invalidly imported constructor identifier in the import. Note that we could provide a better error message here, by suggesting how to import the constructor correctly (e.g. import Prelude (Bool (True)) instead of import Prelude (True) ). |
Few |
Conclusion: In ImportSyntaxCheck errors, it seems useful to encompass the identifier causing an invalid import.
ImpredCheck
Message | Description | Current position | Proposed span | Changes required |
---|---|---|---|---|
errIllegalPolymorphicType |
Impredicative types (such as [forall a. a] ) are not currently supported. |
The impredicative type in the signature. | The impredicative type in the signature. | Few |
errIllegalDefaultType |
Impredicative types cannot be used in a default declaration either. | See above. | See above. | Few |
Conclusion: When emitting errors about unsupported types (such as impredicative types), it seems useful to encompass the invalid type.
InstanceCheck
Message | Description | Current position | Proposed span | Changes required |
---|---|---|---|---|
errMissingInstance |
A superclass instance is missing. | Depending on which check... function invokes errMissingInstance , this could e.g. be the beginning of the instance declaration or a data declaration in the case of derived types. |
The type for which the instance is missing (e.g. C in instance Applicative C where or in data C deriving (Ord) ). |
Possibly changes to DeriveInfo . |
Conclusion: When emitting errors about missing instances, it seems useful to encompass the type for which the instance is missing.
InterfaceCheck
Message | Description | Current position | Proposed span | Changes required |
---|---|---|---|---|
errNotExported |
An interface declares something external that the module does not export. | The incorrectly used type/value in the .icurry file |
The type/value identifier in the .icurry file |
Replacing the HasPosition bounds by HasSpanInfo . |
errNoPrecedence |
No precedence is found for an externally defined operator in an interface. | The beginning of the incorrect precedence declaration in the .icurry file. |
The entire invalid precedence declaration. | In addition to the above, possibly also adding span info to IDecl . |
errNoInstance |
An interface declares an interface for an external type that the module does not declare. | The beginning of the instance declaration in the .icurry file |
The identifier of the incorrectly implemented class in the instance declaration of the .icurry file. |
Few (InstIdent already captures these identifiers) |
errImportConflict |
A re-exporting interface's module declares a type/value differently from it's original definition. | The beginning of the incorrectly re-exported declaration in the .icurry file |
The identifier of the incorrectly re-exported type/value in the .icurry file |
Replacing the HasPosition bounds by HasSpanInfo and passing the relevant identifier. |
These errors can for example be reproduced by removing the import Prelude;
line from a .icurry
file.
Conclusion: When emitting errors in
.icurry
files, in most cases it seems useful to highlight the identifier of the incorrectly declared type/value in question.
InterfaceSyntaxCheck
Message | Description | Current position | Proposed span | Changes required |
---|---|---|---|---|
errUndefined |
An undefined type/class is used (e.g. in an instance declaration) | The undefined type/class' identifier | The undefined type/class' identifier's span | Few |
errMultipleImplementation |
A method is declared multiple times (with different arities) in an instance declaration. | The first occurrence's method identifier. | The first occurrence's method identifier's span. | Few |
errAmbiguousType |
A method's signature does not contain the classe's type variable. | The method identifier. | The method identifier's span. | Few (using IMethodDecl 's identifier span instead of the position) |
errConstrainedClassVariable |
A method constrains a class variable further. | See above. | See above. | See above. |
errNonLinear |
A type variable occurrs more than once in e.g. a data declaration. | The first occurrence of this type variable. | The first occurrence of this type variable. | Few |
errNoVariable |
A previously declared type is used as a type variable. Note that this usually only occurs when the conventions are not followed (e.g. lowercased types). | The invalid type variable's identifier. | The invalid type variable's identifier. | Few |
errUnboundVariable |
An unbound type variable is used (e.g. on the right side of a data declaration). Note that these types are called existentials and are not available in standard Curry. | The unbound type variable. | The unbound type variable. | Few |
errBadTypeSynonym |
A synonym type is incorrectly used in a type constructor. (This is prohibited in .icurry files) |
The invalidly used type synonym identifier in the type constructor. | The invalidly used type synonym identifier in the type constructor. | Few |
errNoElement |
A hidden element is not defined. | The type's identifier in the data declaration in the .icurry file. |
The incorrect constructor's identifier in the {-# HIDING #-} declaration in the .icurry file. |
Few (using x identifier instead of the type) |
errIllegalSimpleConstraint |
A class constraint is not of the form C a (where C is a class and a a type variable). |
The invalid constraint. | The invalid constraint's span. | Few |
errIllegalInstanceType |
An instance type is not of the form (T a_1 ... a_n) with T being a type and a_1 ... a_n type variables. |
The beginning of the invalid instance declaration. | The invalid instance type declaration. | Few (Possibly using the InstanceType 's span instead of the passed instance position) |
Conclusion: When checking instance syntax semantics, the span to use often depends on the specific case.
KindCheck
Message | Description | Current position | Proposed span | Changes required |
---|---|---|---|---|
errRecursiveTypes |
(Possibly mutually) recursive type synonyms | The name of the first occurrence of a (possibly mutually) recursive type | The name of the first occurrence of a (possibly mutually) recursive type | Few |
errRecursiveClasses |
A type class is recursively defined (e.g. class C a => C a ) |
The type class name (the second C a in the example) |
The type class name | Few |
errNonArrowKind |
An arity 0 type cannot take a parameter. | The beginning of the declaration containing the invalidly applied type. | The invalidly applied type itself (analogously to how GHC handles this). | Possibly passing the SpanInfo from ApplyType to kcArrow (KindCheck.hs:618) |
errPartialAlias |
A type has not been applied enough parameters. | See above. | See above. | Possibly passing the SpanInfo from ConstructorType to errPartialAlias (KindCheck.hs:613) |
errKindMismatch |
Two kinds could not be unified (e.g. a 's kind in a b -> a ) |
See above. | See above. | Possibly changing unify 's signature to accept SpanInfo and passing ApplyType 's SpanInfo to unify (KindCheck.hs:620) and using the SpanInfo from TypeExpr in kcTypeSig (KindCheck.hs:582+). |
Conclusion: In the KindCheck, it seems useful to encompass the type (e.g. containing invalid applications). This is analogous to how GHC handles such cases.
PrecCheck
Message | Description | Current position | Proposed span | Changes required |
---|---|---|---|---|
errUndefinedOperator |
No definition for an operator is in scope. | The operator's identifier. | The operator's identifier. | Few |
errMultiplePrecedence |
More than one precedence/associativity declaration for an oeprator is present. | The operator's identifier in the first precedence declaration. | The operator's identifier in the first precedence declaration (which is analogous to how GHC handles this). | Few |
errInvalidParse |
Some operator was used incorrectly. | The invalidly used operator's position. | The invalidly used operator's span. | Few |
errAmbiguousParse |
Some operator was used ambiguously. | The ambiguously used operator's position. | The ambiguously used operator's span. | Few |
Conclusion: In PrecCheck, it generally seems useful to encompass the operator in question.
SyntaxCheck
Message | Description | Current position | Proposed span | Changes required |
---|---|---|---|---|
errUnsupportedFPTerm |
Something (e.g. a lazy pattern) is not supported in a functional pattern. | The beginning of the declaration. | The pattern's span. | Few (using the SpanInfo from the Pattern instead of passing it down) |
errUnsupportedFuncPattern |
Something (e.g. a functional pattern) is not supported in a lazy pattern. | See above. | See above. | See above. |
errFuncPatNotGlobal |
A locally defined function is used in a functional pattern. | The invalid function's identifier inside the pattern. | The invalid function's identifier inside the pattern. | Few |
errFuncPatCyclic |
A function references itself in a pattern. | See above | See above. | Few |
errPrecedenceOutOfRange |
A precedence is outside the range [0, 9]. | The precedence declaration. | The precedence declaration. | Few |
errUndefinedVariable |
A variable is not defined. | The variable's identifier. | The variable's identifier. | Few |
errUndefinedData |
A data constructor is not defined. | The data constructor's identifier. | The data constructor's identifier. | Few |
errUndefinedLabel |
A record label is not defined. | The label's identifier. | The label's identifier. | Few |
errUndefinedMethod |
A method used in an instance declaration is not (visibly) defined in the class. | The undefined method's identifier. | The undefined method's identifier. | Few |
errAmbiguous |
An identifier for something (e.g. a data constructor or label) is ambiguous. | The identifier. | The identifier. | Few |
errDuplicateDefinition |
There is more than one definition for an identifier (e.g. of a local function, which cannot be nondeterministic). | See above. | See above. | Few. |
errDuplicateVariables |
A variable occurs more than once in a pattern. | The variable identifier in the first occurrence. | The variable identifier in the first occurrence. | Few |
errMultipleDataConstructor |
There are multiple definitions for a data/record constructor. | The first constructor's identifier. | The first constructor's identifier. | Few |
errMultipleDeclarations |
Something (e.g. a data type) is defined multiple times. | The type name in the first occurrence. | The type name in the first occurrence. | Few |
errDuplicateTypeSig |
There is more than one type signature for a variable. | The variable's identifier. | The variable's identifier. | Few |
errDuplicateLabel |
A field label occurs more than once in a record declaration. | The identifier of the label's first occurrence. | The identifier of the label's first occurrence. | Few |
errNonVariable |
A data constructor appears in the lhs of a curried definition. | The constructor's identifier. | The constructor's identifier. | Few |
errNoBody |
TODO | TODO | TODO | TODO |
errNoCommonCons |
No constructor exists that has all required labels in a record expression. (e.g. value { x = ..., y = ...} , but `data T = A { x :: ... } |
B { y :: ...}`) | The = in the equation. |
The first of the field identifiers. |
errNoLabel |
An unknown field label is used in a record expression (e.g. T { label = ... } ). |
The unknown label. | The unknown label. | Few |
errNoTypeSig |
An external function has no type signature. | The external function's identifier. | The external function's identifier. | Few |
errToplevelPattern |
A pattern declaration is not allowed at the top level. | The beginning of the equation. | The left-hand side of the equation. | Few (possibly requires using the SpanInfo from the Lhs in checkEqLhs (SyntaxCheck.hs:628, SyntaxCheck.hs:639)) |
errDifferentArity |
A function has multiple equations with different arities. | The function name in the first of the conflicting equations. | The function name in the first of the conflicting equations. | Few |
errWrongArity |
A data constructor is of the wrong arity. | The constructor's identifier where incorrectly applied. | The constructor's identifier where incorrectly applied. | Few |
errMissingLanguageExtension |
A language extension is missing (e.g. FunctionalPatterns ). |
The beginning of the declaration requiring the extension or the free variable (depending on the usage). | For functional patterns, the pattern requiring the extension and otherwise the free variable. | Few (possibly using the second SpanInfo passed to checkInfixPattern in the call to checkFuncPatsExtension (SyntaxCheck.hs:869)) |
errInfixWithoutParens |
Parentheses are missing in an infix pattern. | The operator in the pattern. | The operator in the pattern. | Few (replacing the position by a span info (SyntaxCheck.hs:743)) |
Conclusion: In the SyntaxCheck, there are again different cases where spans should be handled differently. In general though, it seems useful to pick the innermost element that relates to the error generated. Most often, this is the identifier of the type/class/operator in question.
TypeCheck
Message | Description | Current position | Proposed span | Changes required |
---|---|---|---|---|
errPolymorphicVar |
A variable has a polymorphic type. | The variable identifier. | The variable identifier. | Few |
errTypeSigTooGeneral |
A type signature is more general than the inferred one. | The function name. | The type signature. | Few (using the TypeExpr s SpanInfo instead of the function name identifiers) |
errMethodTypeTooSpecific |
A method implements a too specific type. | The function declaration. | The function declaration's span. | Few (use the FunctionDecl 's identifier in checkInstMethodType (TypeCheck.hs:1042)) |
errNonFunctionType |
A non-function type cannot be applied. | The expression's position. | The expression's span. | Few (change tcExpr s (and related) signatures to accept HasSpanInfo ) |
errNonBinaryOp |
A non-operator cannot be used as a binary operator. | See above. | See above. | See above. |
errTypeMismatch |
A type error. | See above. | See above. | See above. |
errSubsumption |
A type is not polymorphic as expected. | See above. | See above. | See above. |
errIncompatibleLabelTypes |
Two labelled types are incompatible. | See above. | See above. | See above. |
errMissingInstance |
An instance is missing. | See above. | See above. | See above. |
errAmbiguousTypeVariable |
A type variable is ambiguous. | The declaration's position. | The declaration's span. | Few (use HasSpanInfo instead of HasPosition where needed) |
Conclusion: In the TypeCheck, it seems useful to encompass the expressions that have mismatching types.
TypeSyntaxCheck
Message | Description | Current position | Proposed span | Changes required |
---|---|---|---|---|
errMultipleDefaultDeclarations |
There is more than one default declaration. | The first default declaration's position. | The first default declaration's span. | Few (pass SpanInfo s instead of Position s to the error function) |
errMultipleDeclarations |
There are multiple declarations of an identifier. | The identifier. | The identifier. | Few |
errMissingLanguageExtension |
A required language extension is missing (e.g. ExplicitForAll or RankNTypes ). |
The invalid type. | The invalid type. | Few (use span info directly instead of fetching the position from it) |
errUndefined |
An identifier is undefined. | The identifier. | The identifier. | Few |
errAmbiguousIndent |
An identifier is ambiguous. | The identifier. | The identifier. | Few |
errAmbiguousType |
A method's signature does not mention a class type variable. | The method's identifier. | The method's identifier. | Few |
errConstrainedClassVariable |
A method context cannot constrain a classes variable. | The invalid type signature's position. | The invalid type signature's span. | Few (use span info directly in checkClassMethod ) |
errNonLinear |
A type variable occurs more than once. | The type variable identifier. | The type variable identifier. | Few |
errNoVariable |
A previously declared type constructor/type class identifier is incorrectly used as a type variable. | The invalid type variable identifier. | The invalid type variable identifier. | Few |
errUnboundVariable |
A type variable is unbound. | The type variable identifier. | The type variable identifier. | Few |
errIllegalConstraint |
A class constraint is ill-formed. | The class identifier. | The class identifier. | Few |
errIllegalSimpleConstraint |
See above. | See above. | See above. | Few |
errIllegalInstanceType |
An instance type is ill-formed. | The instance declaration. | The instance type's span. | Few (use InstType 's span info instead of the passed span in checkInstanceType (TypeSyntaxCheck.hs:444)) |
errIllegalDataInstance |
An instance of a specific class cannot be defined manually. | The class identifier. | The class identifier. | Few |
Conclusion: In the TypeSyntaxCheck, many errors are already generated from identifiers, thus it seems useful to just use those for span information.
WarnCheck
Message | Description | Current position | Proposed span | Changes required |
---|---|---|---|---|
warnMultiplyImportedModule |
A module is imported more than once. | The module identifier. | The module identifier. | Few |
warnMultiplyImportedSymbol |
A symbol from a module is imported more than once. | See above. | See above. | Few |
warnMultiplyHiddenSymbol |
A symbol from a module is hidden more than once. | See above. | See above. | Few |
warnDisjoinedFunctionRules |
Rules for a function are disjoined. | The function name identifier. | The function name identifier. | Few |
warnOrphanInstance |
The orphan instance declaration. | The instance declaration's position. | The implementor type identifier's span in the instance declaration. | Few (pass TypeExpr 's span info in checkDecl (WarnCheck.hs:298)) |
warnMissingMethodImplementation |
A method is missing in the declaration. | See above. | See above. | See above. |
warnMissingTypeSignature |
A top-level binding has no type signature. | The identifier of the binding. | The identifier of the binding. | Few |
warnModuleNameClash |
A module alias overlaps with the current module name. | The clashing module identifier. | The clashing module identifier. | Few |
warnAliasNameClash |
Module aliases overlap. | The first overlapping module identifier. | The first overlapping module identifier. | Few |
warnMissingPattern |
Pattern matches are non-exhaustive. | The case expression. |
The value matched on in the case expression. |
Few (use the Case 's Expression 's span info in checkExpr (WarnCheck.hs:461)) |
warnUnreachablePattern |
A case branch is not reachable. | The first overlapping branch. | The first overlapping branches pattern. | Few (use the span info from pats instead of spis in checkCaseAlts (WarnCheck.hs:604)) |
warnNondetOverlapping |
A case expression is potentially nondeterministic due to overlapping rules. | The case expression. |
The value matched on in the case expression. |
Few (use the Case 's Expression 's span info in checkExpr (WarnCheck.hs:461)) |
warnRedContext |
A redundant context is used somewhere (e.g. a class/instance/type declaration). | The identifier of the declared symbol. | The identifier of the declared symbol. | Few |
warnCaseMode |
An invalid case mode is used in a symbol. | The symbol's identifier. | The symbol's identifier. | Few |
warnUnrefTypeVar |
A type variable is not referenced. | The type variable's identifier. | The type variable's identifier. | Few |
warnUnrefVar |
A variable declaration is not referenced. | The variable identifier. | The variable identifier. | Few |
warnShadowing |
A symbol shadows another. | The shadowing identifier. | The shadowing identifier. | Few |
warnTypeShadowing |
A type variable shadows another. | The shadowing type variable. | The shadowing type variable. | Few |
Conclusion: The WarnCheck already uses identifiers in many places where warnings are generated, so it seems useful to just derive spans from these identifiers. There are some notable exceptions to this though (e.g. not using the entire
Case
expression's span), mostly to keep the span information short. Having short spans keeps the compiler log tidy (especially if/once line previews get implemented) and can potentially mark relevant positions in the source code better.