From 1fd7c5639106800a64cb7e0de9b9db38e3090487 Mon Sep 17 00:00:00 2001 From: Andreas Stadelmeier Date: Wed, 15 May 2024 23:58:52 +0200 Subject: [PATCH] Add Capture Constraint are not reflexive explanation --- conclusion.tex | 2 +- constraints.tex | 53 ++++++++++++++++++++++++++++++++++ introduction.tex | 74 +++++++++++++++--------------------------------- prolog.tex | 5 ++++ soundness.tex | 2 +- tRules.tex | 2 +- unify.tex | 48 +++++++------------------------ 7 files changed, 94 insertions(+), 92 deletions(-) diff --git a/conclusion.tex b/conclusion.tex index 6561e2e..7213dcc 100644 --- a/conclusion.tex +++ b/conclusion.tex @@ -120,7 +120,7 @@ The problems introduced in the openening \ref{challenges} can be solved via our As you can see by the given examples our type inference algorithm can calculate type solutions for programs involving wildcards. -Going further we try to proof soundness and completeness for \unify{}. +Going further we try to prove soundness and completeness for \unify{}. % The tricks are: diff --git a/constraints.tex b/constraints.tex index c60a64f..696d255 100644 --- a/constraints.tex +++ b/constraints.tex @@ -1,3 +1,56 @@ +\section{Capture Constraints} +%TODO: General Capture Constraint explanation + +Capture Constraints are not reflexive. +This is necessary to solve challenge \ref{challenge:1}. +A capture constraint is bound to a specific let statement. +For example the statement \lstinline{let x = v in x.get()} +generates a constraint like $\tv{x} \lessdotCC \exptype{List}{\wtv{a}}$. +This means that the type variable $\tv{x}$ on the left side of the capture constraint is actually a placeholder +for a type that is subject to capture conversion. +It is possible that two syntactically equal capture constraints evolve +during constraint generation or the \unify{} process. +Take the two constraints in listing \ref{lst:sameConstraints} +which originate from the \texttt{concat} method invocation in listing \ref{lst:faultyConcat} for example. +To illustrate their connection to a let statement each capture constraint is annoted with its respective variable. +After a capture conversion step the constraints become +$\exptype{List}{\rwildcard{X}} \lessdot \exptype{List}{\wtv{a}}, +\exptype{List}{\rwildcard{Y}} \lessdot \exptype{List}{\wtv{a}} +$ +making obvious that this constraint set is unsolvable. + +\textit{Note:} +In the special case \lstinline{let x = v in concat(x,x)} the constraint would look like +$\wctype{\rwildcard{X}}{List}{\rwildcard{X}} \lessdotCC_\texttt{x} \exptype{List}{\wtv{a}}, +\wctype{\rwildcard{X}}{List}{\rwildcard{X}} \lessdotCC_\texttt{x} \exptype{List}{\wtv{a}}$ +and we could actually delete one of them without loosing information. +But this case will never occur in our algorithm, because the let statements for our input programs are generated by a ANF transformation (see \ref{sec:anfTransformation}). + +In this paper we do not annotate capture constraint with their source let statement. +Instead we consider every capture constraint as distinct to other constraints even when syntactically the same, +because we know that each capture constraint originates from a different let statement. +\textit{Hint:} An implementation of this algorithm has to consider that seemingly equal capture constraints are actually not the same +and has to allow doubles in the constraint set. + + +\begin{figure} +\begin{minipage}[t]{0.49\textwidth} + \begin{lstlisting}[caption=Faulty Method Call,label=lst:faultyConcat]{tamedfj} +List v = ...; + +let x = v in + let y = v in + concat(x, y) // Error! + \end{lstlisting}\end{minipage} + \hfill + \begin{minipage}[t]{0.49\textwidth} +\begin{lstlisting}[caption=Annotated constraints,mathescape=true,style=constraints,label=lst:sameConstraints] +$\wctype{\rwildcard{X}}{List}{\rwildcard{X}} \lessdotCC_\texttt{x} \exptype{List}{\wtv{a}}$ +$\wctype{\rwildcard{X}}{List}{\rwildcard{X}} \lessdotCC_\texttt{y} \exptype{List}{\wtv{a}}$ + \end{lstlisting} + \end{minipage} +\end{figure} + \section{Constraint generation}\label{chapter:constraintGeneration} % Our type inference algorithm is split into two parts. % A constraint generation step \textbf{TYPE} and a \unify{} step. diff --git a/introduction.tex b/introduction.tex index c22e21a..6f5bff4 100644 --- a/introduction.tex +++ b/introduction.tex @@ -16,6 +16,12 @@ Type inference for Java has many use cases and could be used to help programmers finding better type solutions for already typed Java programs (for example more generical ones), or allowing to write typeless Java code which is then type inferred and thereby type checked by our algorithm. +We propose a global type inference algorithm for Java supporting Wildcards and proven sound. +Global type inference allows input programs without any type annotations. +A programmer could write Java code without stressing about types and type annotations which +are infered and inserted by our algorithm. +%This leads to better types (Poster referenz) + %The algorithm proposed in this paper can determine a correct typing for the untyped Java source code example shown in listing \ref{lst:intro-example-typeless}. %In this case our algorithm would also be able to propose a solution including wildcards as shown in listing \ref{lst:intro-example-typed}. @@ -47,7 +53,7 @@ Also the transformation steps of the \unify{} algorithm are directly related to \item[Java Type Inference] Standard Java provides type inference in a restricted form % namely {Local Type Inference}. -which only works for local environments where the surrounding context has knwon types. +which only works for local environments where the surrounding context has known types. But our global type inference algorithm is able to work on input programs which do not hold any type annotations at all. We will show the different capabilities with an example. In listing \ref{lst:tiExample} the method call \texttt{emptyList} is missing @@ -113,7 +119,7 @@ We present a novel approach to deal with existential types and capture conversio \item The algorithm is split in two parts. A constraint generation step and an unification step. Input language and constraint generations can be extended without altering the unification part. \item -We proof soundness and aim for a good compromise between completeness and time complexity. +We prove soundness and aim for a good compromise between completeness and time complexity. \end{itemize} % Our algorithm finds a correct type solution for the following example, where the Java local type inference fails: % \begin{verbatim} @@ -253,7 +259,7 @@ but there exists some unknown type $\exptype{List}{\rwildcard{A}}$, with $\rwild \texttt{Object}. Inside the body of the let statement \expr{v} is treated as a value with the constant type $\exptype{List}{\rwildcard{A}}$. Existential types enable us to formalize \textit{Capture Conversion}. -Polymorphic method calls need to be wraped in a process which \textit{opens} existential types \cite{addingWildcardsToJava}. +Polymorphic method calls need to be wrapped in a process which \textit{opens} existential types \cite{addingWildcardsToJava}. In Java this is done implicitly in a process called capture conversion (as proposed in Wild FJ \cite{WildFJ}). \begin{figure} @@ -360,6 +366,19 @@ A subtype constraint is satisfied if the left side is a subtype of the right sid Subtype constraints and type placeholders act the same as the ones used in \emph{Type Inference for Featherweight Generic Java} \cite{TIforFGJ}. The novel capture constraints and wildcard placeholders are needed for method invocations involving wildcards. +Our \unify{} process uses a similar concept as the standard unification by Martelli and Montanari \cite{MM82}, +consisting of terms, relations and variables. +Instead of terms we have types of the form $\exptype{C}{\ol{T}}$ and +the variables are called type placeholders. +The input consist out of subtype relations. +The goal is to find a solution (an unifier) which is a substitution for type placeholders +which satisfies all input subtype constraints. +Types are reduced until they %either reach a discrepancy like $\type{String} \doteq \type{Integer}$ +reach a form like $\tv{a} \doteq \type{T}$. +Afterwards \unify{} substitutes type placeholder $\tv{a}$ with $\type{T}$. +This is done until a substitution for all type placeholders and therefore a valid solution is reached. +The reduction and substitutions are done in the first step of the algorithm. + \begin{recap}\textbf{TI for FGJ without Wildcards:} \TFGJ{} generates subtype constraints $(\type{T} \lessdot \type{T})$ consisting of named types and type placeholders. For example the method invocation \texttt{concat(l, new Object())} generates the constraints @@ -433,53 +452,6 @@ $\exptype{List}{\wctype{\rwildcard{X}}{List}{\rwildcard{X}}}$. There is no solution for the subtype constraint: $\exptype{List}{\wctype{\rwildcard{X}}{List}{\rwildcard{X}}} \lessdotCC \exptype{List}{\exptype{List}{\wtv{x}}}$ -% No capture conversion for methods in the same class: -% Given two methods without type annotations like -% \begin{verbatim} -% // m :: () -> r -% m() = new List() :? new List(); - -% // id :: (a) -> a -% id(a) = a -% \end{verbatim} - -% and a method call \texttt{id(m())} would lead to the constraints: -% $\exptype{List}{\type{String}} \lessdot \ntv{r}, -% \exptype{List}{\type{Integer}} \lessdot \ntv{r}, -% \ntv{r} \lessdotCC \ntv{a}$ - -% In this example capture conversion is not applicable, -% because the \texttt{id} method is not polymorphic. -% The type solution provided by \unify{} for this constraint set is: -% $\sigma(\ntv{r}) = \wctype{\rwildcard{X}}{List}{\rwildcard{X}}, -% \sigma(\ntv{a}) = \wctype{\rwildcard{X}}{List}{\rwildcard{X}}$ -% \begin{verbatim} -% List m() = new List() :? new List(); -% List id(List a) = a -% \end{verbatim} - -% The following example has the \texttt{id} method already typed and the method \texttt{m} -% extended by a recursive call \texttt{id(m())}: -% \begin{verbatim} -% List id(List a) = a - -% m() = new List() :? new List() :? id(m()); -% \end{verbatim} -% Now the constraints make use of a $\lessdotCC$ constraint: -% $\exptype{List}{\type{String}} \lessdot \ntv{r}, -% \exptype{List}{\type{Integer}} \lessdot \ntv{r}, -% \ntv{r} \lessdotCC \exptype{List}{\wtv{a}}$ - -% After substituting $\wctype{\rwildcard{X}}{List}{\rwildcard{X}}$ for $\ntv{r}$ like in the example before -% we get the constraint $\wctype{\rwildcard{X}}{List}{\rwildcard{X}} \lessdotCC \exptype{List}{\wtv{a}}$. -% Due to the $\lessdotCC$ \unify{} is allowed to perform a capture conversion yielding -% $\exptype{List}{\rwildcard{X}} \lessdot \exptype{List}{\wtv{a}}$. -% \textit{Note:} The wildcard placeholder $\wtv{a}$ is allowed to hold free variables whereas a normal placeholder like $\ntv{r}$ -% is never assigned a type containing free variables. -% Therefore \unify{} sets $\wtv{a} \doteq \rwildcard{X}$, completing the constraint set and resulting in the type solution: -% \begin{verbatim} -% List m() = new List() :? new List() :? id(m()); -% \end{verbatim} \subsection{Challenges}\label{challenges} %TODO: Wildcard subtyping is infinite see \cite{TamingWildcards} @@ -498,7 +470,7 @@ A problem arises when replacing type variables with wildcards. Lets have a look at a few challenges: \begin{itemize} -\item +\item \label{challenge:1} One challenge is to design the algorithm in a way that it finds a correct solution for the program shown in listing \ref{lst:addExample} and rejects the program in listing \ref{lst:concatError}. The first one is a valid Java program, diff --git a/prolog.tex b/prolog.tex index 5038afa..262cc6f 100755 --- a/prolog.tex +++ b/prolog.tex @@ -11,11 +11,16 @@ escapeinside={(*@}{@*)}, captionpos=t,float,abovecaptionskip=-\medskipamount } + \lstdefinestyle{fgj}{backgroundcolor=\color{lime!20}} \lstdefinestyle{tfgj}{backgroundcolor=\color{lightgray!20}} \lstdefinestyle{letfj}{backgroundcolor=\color{lime!20}} \lstdefinestyle{tamedfj}{backgroundcolor=\color{yellow!20}} \lstdefinestyle{java}{backgroundcolor=\color{lightgray!20}} +\lstdefinestyle{constraints}{ + basicstyle=\normalfont, + backgroundcolor=\color{red!20} +} \newtheorem{recap}[note]{Recap} diff --git a/soundness.tex b/soundness.tex index 9077034..ae68ebf 100644 --- a/soundness.tex +++ b/soundness.tex @@ -152,7 +152,7 @@ By structural induction over the expression $\texttt{e}$. % $\sigma(\ol{\tv{r}}) = \overline{\wcNtype{\Delta}{N}}$, % $\ol{N} <: [\ol{S}/\ol{X}]\ol{U}$, % TODO: S ok? We could proof $\Delta, \Delta' \overline{\Delta} \vdash \ol{S} \ \ok$ - % by proofing every substitution in Unify is ok aslong as every type in the inputs is ok + % by proving every substitution in Unify is ok aslong as every type in the inputs is ok % S ok when all variables are in the environment and every L <: U and U <: Class-bound % This can be given by the constraints generated. We can proof if T ok and S <: T and T <: S' then S ok and S' ok diff --git a/tRules.tex b/tRules.tex index 8da4174..d0ddf93 100644 --- a/tRules.tex +++ b/tRules.tex @@ -35,7 +35,7 @@ Our algorithm is designed for extensibility with the final goal of full support Additional language constructs can be added by implementing the respective constraint generation functions in the same fashion as described in chapter \ref{chapter:constraintGeneration}. %\textit{Note:} \item The typing rules for expressions shown in figure \ref{fig:expressionTyping} refrain from restricting polymorphic recursion. -Type inference for polymorphic recursion is undecidable \cite{wells1999typability} and when proofing completeness like in \cite{TIforFGJ} the calculus +Type inference for polymorphic recursion is undecidable \cite{wells1999typability} and when proving completeness like in \cite{TIforFGJ} the calculus needs to be restricted in that regard. Our algorithm is not complete (see discussion in chapter \ref{sec:completeness}) and without the respective proof we can keep the \TamedFJ{} calculus as simple as possible and as close to it's Featherweight Java correspondent \cite{WildcardsNeedWitnessProtection} as possible. diff --git a/unify.tex b/unify.tex index 893a0a7..6743afc 100644 --- a/unify.tex +++ b/unify.tex @@ -175,7 +175,7 @@ and $\wctype{\wildcard{Y}{\type{Object}}{\tv{String}}}{List}{\rwildcard{Y}} \les We define two types as equal if they are mutual subtypes of each other. %This relation is symmetric, reflexive and transitive by the definition of subtyping. -%This definition is sufficient for proofing soundness. +%This definition is sufficient for proving soundness. \begin{definition}{Type Equality:}\label{def:equal} $\Delta \vdash \type{S} = \type{T}$ if $\Delta \vdash \type{T} <: \type{S}$ and $\Delta \vdash \type{T} <: \type{S}$ \end{definition} @@ -279,34 +279,15 @@ The normal type placeholder $\ntv{r}$ has to be replaced by a type without free %\newcommand{\tw}[1]{\tv{#1}_?} \begin{description} \item[Input:] An environment $\Delta'$ -and a set of constraints $C = \set{ \type{T} \lessdot \type{T}, \type{T} \doteq \type{T} \ldots}$ -and a list of constraints $C' = \set{ \type{T} \lessdotCC \type{T}}$. -The input constraints must be of the following format: - -\begin{tabular}{lcll} - $c $ &$::=$ & $\type{T} \lessdot \type{T}, \type{T} \lessdotCC \type{T}$ & Constraint \\ - $\type{T}, \type{U}, \type{L} $ & $::=$ & $\ntv{a} \mid \wtv{a} \mid \ntype{N}$ & Type variable or Wildcard Variable or Type \\ - $\ntype{N}, \ntype{S}$ & $::=$ & $\wctype{\overline{\wildcard{X}{U}{L}}}{C}{\ol{T}} $ & Class Type \\ -\end{tabular}\\[0.5em] +and a set of constraints $C = \set{ \type{T} \lessdot \type{T}, \type{T} \lessdotCC \type{T}, \type{T} \doteq \type{T} \ldots}$ \item[Output:] Set of unifiers $Uni = \set{\sigma_1, \ldots, \sigma_n}$ and an environment $\Delta$ \end{description} -The \unify{} algorithm internally uses the following data types: - -\begin{tabular}{lcll} - $C $ &$::=$ &$\overline{c}$ & Constraint set \\ - $c $ &$::=$ & $\type{T} \lessdot \type{T} \mid \type{T} \lessdotCC \type{T} \mid \type{T} \doteq \type{T}$ & Constraint \\ - $\type{T}, \type{U}, \type{L} $ & $::=$ & $\tv{a} \mid \gtype{G}$ & Type placeholder or Type \\ - $\tv{a}$ & $::=$ & $\ntv{a} \mid \wtv{a}$ & Normal and wildcard type placeholder \\ - $\gtype{G}$ & $::=$ & $\type{X} \mid \ntype{N}$ & Wildcard, or Class Type \\ - $\ntype{N}, \ntype{S}$ & $::=$ & $\wctype{\triangle}{C}{\ol{T}} $ & Class Type \\ - $\triangle$ & $::=$ & $\overline{\wtype{W}}$ & Wildcard Environment \\ - $\wtype{W}$ & $::=$ & $\wildcard{X}{U}{L}$ & Wildcard \\ -\end{tabular} - -The algorithm is split into multiple parts: +Each calculation step of the algorithm is expressed as a transformation rule. +% TODO: Explain syntax of the transformation steps +The transformation steps are not applied all at once but in a specific order: \begin{description} \item[Step 1:] Apply the rules depicted in the figures \ref{fig:normalizing-rules}, \ref{fig:reduce-rules} and \ref{fig:wildcard-rules} exhaustively, @@ -1371,23 +1352,13 @@ $ \caption{Type Reduction rules}\label{fig:reductionRules} \end{figure} -\subsection{Explanation} -Our \unify{} process uses a similar concept to the standard unification by Martelli and Montanari \cite{MM82}, -consisting of terms, relations and variables. -Instead of terms we have types of the form $\exptype{C}{\ol{T}}$ and -the variables are called type placeholders. -The input consist out of subtype relations. -The goal is to find a solution (an unifier) which is a substitution for type placeholders -which satisfies all input subtype constraints. - -Types are reduced until they %either reach a discrepancy like $\type{String} \doteq \type{Integer}$ -reach a form like $\tv{a} \doteq \type{T}$. -Afterwards \unify{} substitutes type placeholder $\tv{a}$ with $\type{T}$. -This is done until a substitution for all type placeholders and therefore a valid solution is reached. -The reduction and substitutions are done in the first step of the algorithm. +\subsection{Explanations} %The type reduction is done by the rules in figure \ref{fig:reductionRules} +\begin{description} +\item[Prepare] +The \rulename{Prepare} transformation is always applied together with the \rulename{Reduce} transformation. \unify{} cannot reduce constraints without checking a few prerequisites. Take the constraint $\wctype{\rwildcard{X}}{C}{\rwildcard{X}} \lessdot \exptype{C}{\wtv{a}}$ for example. If we apply a reduction here we get $\rwildcard{X} \doteq \wtv{a}$. @@ -1399,6 +1370,7 @@ Therefore the \rulename{Reduce} rule only reduces constraints where the left sid But if the right side neither contains wildcard type placeholders nor free variables the constraint can be reduced anyways. The \rulename{Prepare} rule then converts this constraint to a capture constraint. Afterwards the \rulename{Capture} rule removes the wildcard declarations on the left side an the constraint can be reduced. +\end{description} \textit{Example} of the type reduction rules in figure \ref{fig:reductionRules} with the input $\wctype{\rwildcard{X}}{Pair}{\wctype{\rwildcard{Y}}{List}{\rwildcard{Y}}, \rwildcard{X}} \lessdot \exptype{Pair}{\wctype{\rwildcard{Y}}{List}{\rwildcard{Y}}, \wtv{a}}$