This thesis is about methods for establishing semantic properties of programs and
how those methods can be strengthened. Finding (semi-)algorithms for deciding
semantic properties is a non-trivial task and such algorithms will, by necessity,
give approximate answers. This means that for any property of interest, there is
a spectrum of algorithms computing answers to various degrees of precision,
ranging from computationally cheap, low-precision algorithms to expensive,
potentially non-terminating algorithms with very high precision. Finding
approximations precise enough to be useful, and that at the same time make the
algorithms cheap enough, is a real challenge.
In this thesis we consider program analysis and program verification, which are
two approaches for establishing program properties with contrasting requirements
regarding precision and cost. Program analysis consists of automatic and
computationally cheap algorithms that terminate for all programs and whose prime
usage is in situations where runtime is a major factor or where only limited
resources are available. Program verification by deduction based on logic and
theorem proving gives higher precision but is expensive and have no termination
guarantee. It is often used in situations where it is more costly to modify the
program than allowing the verification process more time and resources.
Common to these two approaches is the desire to move closer to the middle of the
spectrum of algorithms. For algorithms formulated as program analyses, this means
increasing their precision, and for algorithms formulated as program verifiers,
it means making them terminate without user interaction for a larger set of programs.
The work presented in this thesis can be divided into three parts. The first part
investigates the impact a number of features have on the precision of a type-based
program analysis for Haskell. The results presented, make it easier for a designer
of a type-based program analysis to choose what features to add to the analysis in
order to get sufficiently high precision.
The second part concerns how program verification can be integrated with program
analysis in order to make the verification cheaper and more automatic. We show how
a program analysis can be embedded in the tactic language of a theorem prover to
allow for a close integration of program analysis and verification. We also show,
in particular, how a dependence analysis can be used in a theorem prover for Java
to make the handling of loops more automatic.
The third part concerns how type-based program analysis can be strengthened by
plugging in additional, externally computed information. We do this by presenting
a modular method for parameterizing type-based program analyses over information
about the analyzed program's execution. The parameterization is done in such a way
that a modular proof of correctness is obtained, removing the need to prove
correctness of each instantiation separately. We also show how our method of
parameterization can be used to allow for flow-sensitive heap types by plugging in
alias information.