Notes, Warnings and Errors¶
The compiler provides a framework for handling notes, warnings and errors as they’re encountered and created during the compilation process.
This code can be found in the dfmc-conditions library. Initial skeletal API documentation for this library can be found at The DFMC-CONDITIONS API Reference.
Conceptually, all notes, warnings and errors are subtypes of
<condition>
, so we will often refer to them collectively
as program conditions or instances of <program-condition>
.
Status of this Library¶
This library is interesting (to some) as it is in a half-completed state and many things are not yet fully implemented or used. We will try to note these things below when we discuss them.
Philosophy¶
The Open Dylan compiler tries hard not to abort compilation when an error is noted. This leads to many things that might be fatal errors elsewhere being represented as serious warnings here. For example, an undefined variable reference does not abort compilation, but if the code containing that reference is executed it causes a crash at run time.
This was part of a very exploratory development model under the Open Dylan IDE, where many errors could be corrected while an application was running.
This workflow isn’t commonly used with Dylan today, so we may revise this philosophy and how it applies to the compiler’s handling of program conditions, or at least make it configurable.
Similarly, a key element to how program conditions are currently used today is that when we store values on them, we store them as the raw object so that they’re readily accessible from within the debugger, rather than only storing the string representations.
Program Condition Hierarchy¶
The root of the condition hierarchy is <program-condition>
.
This is an abstract class and one of the subclasses such as
<program-note>
, <program-error>
or
<program-restart>
should be subclassed instead.
Reporting a Program Condition¶
The typical way to report that a program condition has arisen
is to use note
. There are other mechanisms, such as
raise
, restart
, simple-note
and simple-raise
,
but these are not in common usage.
For proper error reporting, you will want to try to report as accurate a source location as you possibly can. This can be tricky at first, so look at other similar warnings if you need the assistance.
The actual code for noting a program condition is pretty straightforward, once you’ve identified the location to emit the program condition, and the type of program condition to emit.
note(<wrong-type-in-assignment>,
variable-name: the-name,
type: binding-type,
rhs: rhs-value,
source-location: fragment-source-location(fragment));
Source Locations¶
There are a couple of useful rules to follow for getting source locations for noting a program condition during compilation.
If you’re in C-FFI, you’re probably working with fragments, and so
fragment-source-location
is the right function.If you’re in
dfmc-definitions
, then you probably also wantfragment-source-location
.If you’re in conversion, you may be dealing with either fragments or model objects. For fragments, you want
fragment-source-location
. For model objects, you wantmodel-source-location
.If you’re in
dfmc-optimization
, then you likely wantdfm-source-location
if you’re working with an object that is part of the control flow or data flow graphs, like any computation or temporary. However, in some cases, you’ll still be working with model objects, so keep an eye out for when you need to usemodel-source-location
.
Defining a new Program Condition¶
Depending on where you are defining your new program condition within the Program Condition Hierarchy, you will need to use the appropriate program condition definer:
An example definition looks like:
define program-warning <ambiguous-copy-down-method>
slot condition-method, required-init-keyword: meth:;
slot condition-other-methods, required-init-keyword: other-methods:;
format-string "Multiple applicable copy-down methods for %s, picking one at random";
format-arguments meth;
end;
An interesting thing to note here is that the other-methods are being
recorded by this <program-note>
even though they are not used
within the formatted output. This is because the additional values can
be useful when viewing the condition within the debugger or by other
programmatic processing such as filtering.
PPML, Pretty Print Markup Language¶
When conditions are stored, their slots are converted to PPML
objects. Many objects within the compiler are already configured
to be able to generate PPML via the many specializations of
as(class == <ppml>, ...)
that can be found within the
dfmc-debug-back-end
(see print-condition.dylan).
Slots are converted to PPML representations via code that
is autogenerated by the various definer macros which create
a specialization on convert-condition-slots-to-ppml
.
Filtering of Program Conditions¶
This is functionality that has not been completed and is currently not entirely in use.
To be written.
How Warnings Are Displayed and Recorded¶
To be written.
Responding to a Program Condition¶
In Dylan, the condition system allows for responses to conditions
and can restart a computation with new information. While parts
of dfmc-conditions
are designed to permit this, this functionality,
has never been completed and is not yet working.
Future Work¶
Look at cleaning up unused API and things that are no longer necessary.
obsolete-condition?
is probably obsolete.format-condition
and related code including<detail-level>
are probably no longer necessary with the code indfmc-debug-back-end
and the specialization onprint-object
present there.The specialization on
print-object
can probably go away.simple-note
andsimple-raise
can go away.There is a comment in
dfmc/conversion/convert.dylan
that the presence ofdfm-context-id
is a hack until true source locations are available. Should we removecontext-id
and the supporting code? (On a related note, does that implementation ofdfm-context-id
even work?
Complete other parts of the implementation:
Program condition filtering.
Program restarts.
Make
<program-error>
distinct from a serious warning. This would also need a change todfmc-debug-back-end
and a specialization oncondition-classification
.Use more of the various subclasses of
<program-note>
like the style, performance and portability notes. This requires getting the filtering to work.The implementation doesn’t use limited collection types where it can.
The DFMC-CONDITIONS API Reference¶
Definers for new Program Conditions¶
- program-condition-definer Macro¶
- Macro Call:
define [modifier*] program-condition *class-name* (*superclasses*) *slot-spec* format-string *string*; format-arguments *slot*, ...; filter *filter*; end program-note;
- Parameters:
modifier – One or more class adjectives. bnf
class-name – A valid Dylan class name. bnf
superclasses – One or more Dylan class names to be used as the superclasses for the newly created program condition.
slot-spec – A slot specification.
format-string – A format string valid for use with
format
.format-arguments – One or more parameters which will be passed to
format
along with the format-string. The parameter values will be drawn from the corresponding slots.filter – A Dylan expression to be used as the value for
program-note-filter
on the new class. This should either be#f
or an instance of<function>
which returns a boolean value.
- Discussion:
This is not typically used outside of the
dfmc-conditions
library. It is used for creating a new direct subclass of<program-condition>
. Most often,program-note-definer
or a similar more specific definer macro would be used instead.Any additional slot specifications will be modified slightly:
The
constant
adjective will be removed if present.The type constraint for the slot will be a type union with
<ppml>
.
- program-note-definer Macro¶
- Macro Call:
define [modifier*] program-note *class-name* *slot-spec* format-string *string*; format-arguments *slot*, ...; filter *filter*; end program-note; define [modifier*] program-note *class-name* (*superclasses*) *slot-spec* format-string *string*; format-arguments *slot*, ...; filter *filter*; end program-note;
- Discussion:
Create a new
<program-note>
subclass.
- performance-note-definer Macro¶
- Discussion:
Create a new
<performance-note>
subclass. Seeprogram-note-definer
for details.
- portability-note-definer Macro¶
- Discussion:
Create a new
<portability-note>
subclass. Seeprogram-note-definer
for details.
- program-error-definer Macro¶
- Discussion:
Create a new
<program-error>
subclass. Seeprogram-note-definer
for details.
- program-restart-definer Macro¶
- Discussion:
Create a new
<program-restart>
subclass. Seeprogram-note-definer
for details.
- program-warning-definer Macro¶
- Discussion:
Create a new
<program-warning>
subclass. Seeprogram-note-definer
for details.
- run-time-error-warning-definer Macro¶
- Discussion:
Create a new
<run-time-error-warning>
subclass. Seeprogram-note-definer
for details.
- serious-program-warning-definer Macro¶
- Discussion:
Create a new
<serious-program-warning>
subclass. Seeprogram-note-definer
for details.
- style-warning-definer Macro¶
- Discussion:
Create a new
<style-warning-note>
subclass. Seeprogram-note-definer
for details.
- program-condition-definer-definer Macro¶
- Discussion:
This is not commonly used outside of
dfmc-conditions
. It is creating new program-conditioner definer macros.
Program Conditions¶
- <program-condition> Open Abstract Class¶
- Superclasses:
- Init-Keywords:
compilation-stage – Defaults to the value of
*current-stage*
.program-note-creator – Defaults to the value of
*current-dependent*
.source-location – Defaults to
#f
. Every effort should be made to supply a valid value for this keyword.
- Discussion:
The root of the hierarchy is
<program-condition>
. All errors, warnings, etc, about code in a program being compiled should be reported as instances of this class.This class should only be used for type declarations and as the superclass for mixin properties. For instantiable classes, it’s best to subclass one of
<program-error>
,<program-note>
, or<program-restart>
instead.
- <program-notes> Type¶
- Supertypes:
- <program-note> Open Primary Abstract Class¶
- Superclasses:
- Init-Keywords:
- Discussion:
When a context-id has been supplied, this is used to give an indication of the logical context of the source that the note is about, typically to give a concise textual hint, allowing for example (where
"process-foo"
is the context-id:foo.dylan:180:Warning in process-foo: Bogus call to bar.
- <program-error> Open Abstract Class¶
- Superclasses:
- Discussion:
A
<program-error>
is a language error. Examples would be (most) syntax errors, inconsistent direct superclasses, or a reference to an undefined name.
- <program-restart> Open Primary Abstract Class¶
- Superclasses:
- Init-Keywords:
default
- Discussion:
A
<program-restart>
is a<restart>
meant to be used as part of the recovery protocol for some<program-condition>
.
- <program-warning> Open Abstract Class¶
- Superclasses:
- Discussion:
A <program-warning> is a note about something that might be a mistake in program, but the compiler is able to compile it without intervention.
- <run-time-error-warning> Open Abstract Class¶
- Superclasses:
- Discussion:
Run-time-error warnings are given when the compiler can prove that executing the code will lead definitely lead to a run-time error, whether or not that error is handled. These warnings should be hard for the user to suppress. It should be possible for a user to treat these warnings as errors; that is, stop the compilation process because of one.
- <serious-program-warning> Open Abstract Class¶
- Superclasses:
- <style-warning> Open Abstract Class¶
- Superclasses:
- Discussion:
Style warnings are given when the compiler detects code in a style that is legal (strictly speaking), but not desirable. The display of style warnings can be inhibited globally, or on a class-by-class basis.
- <performance-note> Open Abstract Class¶
- Superclasses:
- Discussion:
Performance notes are given when the compiler is prevented from doing an optimization that should be reasonable or expected in the current context. Typical reasons would be that it has insufficient type, sealing, or program flow information.
- <portability-note> Open Abstract Class¶
- Superclasses:
- Discussion:
Portability notes are given when the compiler detects something that is valid in the Open Dylan compiler, but is not part of portable Dylan or could have undefined effects in Dylan.
It should be possible to turn these warnings into errors, to support a standards-conforming version of the compiler.
Program Condition Slots¶
- condition-compilation-stage Generic function¶
- Signature:
condition-compilation-stage (object) => (value)
- Parameters:
object – An instance of
<program-condition>
.
- Values:
value – An instance of
<object>
.
- condition-context-id Generic function¶
- Signature:
condition-context-id (object) => (value)
- Parameters:
object – An instance of
<program-note>
.
- Values:
value – An instance of
<object>
.
- condition-program-note-creator Generic function¶
- Signature:
condition-program-note-creator (object) => (value)
- Parameters:
object – An instance of
<program-condition>
.
- Values:
value – An instance of
<object>
.
- condition-source-location Generic function¶
- Signature:
condition-source-location (object) => (value)
- Parameters:
object – An instance of
<program-condition>
.
- Values:
value – An instance of
<object>
.
Signaling Program Conditions¶
- note Open Generic function¶
- Signature:
note (class #key #all-keys) => ()
- Parameters:
class – An instance of
subclass(<program-condition>)
.
- Discussion:
The primary program condition signaling interface is
note
, which callsmake
on the condition class and signals it, possibly returning. It can be used for any program condition, but is mainly oriented towards<program-note>
.- Example:
note(<inaccessible-open-definition>, binding: form-variable-binding(form), source-location: form-source-location(form));
- note(subclass(<program-condition>)) Method¶
- maybe-note Macro¶
- raise Open Generic function¶
- Signature:
raise (class #key #all-keys) => ()
- Parameters:
class – An instance of
subclass(<program-condition>)
.
- Discussion:
This function is analogous to the standard Dylan
error
function and is guaranteed to not return.
- raise(subclass(<program-error>)) Method¶
- restart Open Generic function¶
- Signature:
restart (class #key #all-keys) => ()
- Parameters:
class – An instance of
subclass(<program-restart>)
.
- restart(subclass(<program-restart>)) Method¶
Preserving Program Conditions¶
Program conditions are tracked in each library. They are stored in
a table that is associated with each <library-description>
via library-conditions-table
. There are implementations of
another generic function, remove-dependent-program-conditions
which is commonly invoked during retraction. (What retraction
is for isn’t clear to me at this point.)
- add-program-condition Generic function¶
- Signature:
add-program-condition (condition) => ()
- Parameters:
condition – An instance of
<condition>
.
- Discussion:
Records a program condition. This does not usually need to be invoked directly outside of
dfmc-conditions
where it is usually invoked during the filtering of a program condition.
- add-program-condition(<condition>) Method¶
- Discussion:
Runtime errors that are not
<program-condition>
are not currently tracked. This method doesn’t record them.
- add-program-condition(<program-condition>) Method¶
- Discussion:
Preserves a program condition by storing it in the
library-conditions-table
for the current library being compiled.
Recovery and Restarting¶
- condition-block Macro¶
- *error-recovery-model* Variable¶
Subnotes¶
This is a very rarely used capability within the program condition system and isn’t currently well supported by the compiler output to standard out and standard error.
Any <program-note>
can have additional notes attached to it.
These notes are useful for attaching extra data to a note, like possible
options or the sets of conflicting items.
An example usage of subnotes is:
note(<ambiguous-copy-down-method>,
meth: m,
other-methods: others,
source-location: m.model-source-location,
subnotes: map(method (m)
make(<ambiguous-copy-down-method-option>,
meth: m,
source-location: m.model-source-location)
end,
others));
Note
Subnotes are not displayed by the default printing of
program conditions by the command line compiler. They can be
found in the condition log file that is created during the
build process. (_build/build/foo/foo.log
)
- subnotes Generic function¶
- Signature:
subnotes (object) => (value)
- Parameters:
object – An instance of
<program-note>
.
- Values:
value – An instance of
<program-notes>
.
- note-during Macro¶
- accumulate-subnotes-during Macro¶
- *subnotes-queue* Thread Variable¶
Printing Program Conditions¶
- *detail-level* Thread Variable¶
- Type:
- Discussion:
Note
This is currently ignored.
- <detail-level> Type¶
- Equivalent:
one-of(#"terse", #"normal", #"verbose")
- Discussion:
A simple, three-tiered approach to the amount of detail a condition presents.
Note
This is currently ignored.
- Operations:
- format-condition Generic function¶
- Signature:
format-condition (stream condition detail-level) => ()
- Parameters:
stream – An instance of
<stream>
.condition – An instance of
<program-condition>
.detail-level – An instance of
<detail-level>
.
- Discussion:
This calls
format
to write to thestream
. The format string and arguments come from the condition’scondition-format-string
andcondition-format-arguments
respectively.
- print-object(<program-condition>, <stream>) Method¶
- Signature:
print-object (condition, stream) => ()
- Parameters:
condition – An instance of
<program-condition>
.stream – An instance of
<stream>
.
- Discussion:
This calls
format-condition
with a detail-level of#"terse"
.This is provided for integrating program condition printing with the usual mechanisms for formatted output.
Note
This is not actually called often at all as there is a more specific specialization on
<program-note>
defined indfmc-debug-back-end
.
Unclassified API¶
- $record-program-note Constant¶
- $signal-program-error Function¶
- Signature:
$signal-program-error (c) => ()
- Parameters:
c – An instance of
<condition>
.
- $signal-program-note Function¶
- Signature:
$signal-program-note (c) => ()
- Parameters:
c – An instance of
<condition>
.
- <ignore-serious-note> Class¶
- Superclasses:
- Init-Keywords:
format-string
note
- <program-note-filter> Constant¶
- convert-condition-slots-to-ppml Generic function¶
- Signature:
convert-condition-slots-to-ppml (condition) => ()
- Parameters:
condition – An instance of
<condition>
.
- Discussion:
Converts all slots on a condition to their PPML representation. This is typically autogenerated by the various program condition definer macros. It is called from
add-program-condition
.
- convert-condition-slots-to-ppml(<condition>) Method¶
- convert-condition-slots-to-ppml(type-union(<simple-condition>, <simple-error>, <simple-warning>)) Method¶
- convert-condition-slots-to-ppml(<program-note>) Method¶
- convert-condition-slots-to-ppml(<program-restart>) Method¶
- convert-condition-slots-to-ppml(<program-warning>) Method¶
- convert-condition-slots-to-ppml(<serious-program-warning>) Method¶
- convert-condition-slots-to-ppml(<program-error>) Method¶
- convert-condition-slots-to-ppml(<run-time-error-warning>) Method¶
- convert-condition-slots-to-ppml(<style-warning>) Method¶
- convert-condition-slots-to-ppml(<performance-note>) Method¶
- convert-condition-slots-to-ppml(<portability-note>) Method¶
- convert-condition-slots-to-ppml(<ignore-serious-note>) Method¶
- convert-slots-to-ppml Macro¶
- dfmc-continue Thread Variable¶
- dfmc-restart Thread Variable¶
- do-with-program-conditions Function¶
- interesting-note? Generic function¶
- Signature:
interesting-note? (note) => (interesting?)
- Parameters:
note – An instance of
<program-note>
.
- Values:
interesting? – An instance of
<boolean>
.
- Discussion:
True if the note is interesting to the user, according to the yet-to-be-defined compiler policy object. Uninteresting conditions are suppressed, either by not printing messages for them or not logging them at all. Because all errors and restarts are serious, they are also interesting.
- interesting-note?(<program-note>) Method¶
- Parameters:
note – An instance of
<program-note>
.
- Values:
interesting? – Always returns
#t
.
- interesting-note?(<performance-note>) Method¶
- Parameters:
note – An instance of
<performance-note>
.
- Values:
interesting? – Always returns
#f
.
- make-program-note-filter Generic function¶
- Signature:
make-program-note-filter (#key file-name from to in class action) => (filter)
- Parameters:
file-name (#key) – An instance of
<string>
.from (#key) – An instance of
<integer>
.to (#key) – An instance of
<integer>
.in (#key) – An instance of
<string>
.class (#key) – An instance of
subclass(<condition>)
.action (#key) – An instance of
<function>
.
- Values:
filter – An instance of
<program-note-filter>
.
- obsolete-condition? Open Generic function¶
- Signature:
obsolete-condition? (condition) => (obsolete?)
- Parameters:
condition – An instance of
<program-condition>
.
- Values:
obsolete? – An instance of
<boolean>
.
- obsolete-condition?(<program-condition>) Method¶
- Parameters:
condition – An instance of
<program-condition>
.
- Values:
obsolete? – Always returns
#f
.
- Discussion:
Note
This is never used.
- present-program-error Generic function¶
- Signature:
present-program-error (condition) => ()
- Parameters:
condition – An instance of
<condition>
.
- present-program-error(<condition>) Method¶
- present-program-error(<program-note>) Method¶
- present-program-note Generic function¶
- Signature:
present-program-note (condition) => ()
- Parameters:
condition – An instance of
<condition>
.
- present-program-note(<condition>) Method¶
- present-program-note(<program-note>) Method¶
- program-note-class-= Function¶
- Signature:
program-note-class-= (class) => (pred)
- Parameters:
class – An instance of
subclass(<condition>)
.
- Values:
pred – An instance of
<function>
.
- program-note-file-name-= Function¶
- Signature:
program-note-file-name-= (file-name) => (pred)
- Parameters:
file-name – An instance of
<string>
.
- Values:
pred – An instance of
<function>
.
- program-note-filter Open Generic function¶
- Signature:
program-note-filter (class) => (filter)
- Parameters:
class – An instance of
subclass(<condition>)
.
- Values:
filter – An instance of
<program-note-filter>
.
- program-note-filter(subclass(<program-note>)) Method¶
- program-note-filter(subclass(<condition>)) Method¶
- program-note-filter(subclass(<program-warning>)) Method¶
- program-note-filter(subclass(<serious-program-warning>)) Method¶
- program-note-filter(subclass(<run-time-error-warning>)) Method¶
- program-note-filter(subclass(<style-warning>)) Method¶
- program-note-filter(subclass(<performance-note>)) Method¶
- program-note-filter(subclass(<portability-note>)) Method¶
- program-note-filter-setter Open Generic function¶
- Signature:
program-note-filter-setter (filter class) => (filter)
- Parameters:
filter – An instance of
<program-note-filter>
.class – An instance of
subclass(<program-condition>)
.
- Values:
filter – An instance of
<program-note-filter>
.
- program-note-filter-setter(<program-note-filter>, subclass(<program-condition>)) Method¶
- program-note-in Function¶
- Signature:
program-note-in (form) => (pred)
- Parameters:
form – An instance of
<string>
.
- Values:
pred – An instance of
<function>
.
- program-note-location-between Function¶
- Signature:
program-note-location-between (from to) => (pred)
- Parameters:
- Values:
pred – An instance of
<function>
.
- report-condition Open Generic function¶
- Signature:
report-condition (condition) => ()
- Parameters:
condition – An instance of
<condition>
.
- serious-note? Generic function¶
- Signature:
serious-note? (note) => (serious?)
- Parameters:
note – An instance of
<program-note>
.
- Values:
serious? – An instance of
<boolean>
.
- Discussion:
True if this note is serious – that is, requires terminating the current processing and picking a restart. The default behavior is that notes are not serious, but the policy object should allow upgrading them, with options like “all warnings are errors” for making
<program-warning>
serious, or “strict Dylan” for making<portability-note>
serious.Errors are always serious, by definition, because the compiler can’t just skip them. Restarts are always serious, as much as such a definition make sense for them.
- serious-note?(<program-note>) Method¶
- Parameters:
note – An instance of
<program-note>
.
- Values:
serious? – Always returns
#f
.
- serious-note?(<program-error>) Method¶
- Parameters:
note – An instance of
<program-error>
.
- Values:
serious? – Always returns
#t
.
- serious-note?(<serious-program-warning>) Method¶
- Parameters:
note – An instance of
<serious-program-warning>
.
- Values:
serious? – Always returns
#t
.
- simple-note Generic function¶
- simple-raise Generic function¶
- with-program-conditions Macro¶
- with-simple-abort-retry-restart Macro¶