@@ -90,7 +90,7 @@ class AdtEncoder(val program: Program) extends AdtNameManager {
9090 val domain = Domain (name, null , null , typVars)(adt.pos, adt.info, adt.errT)
9191 val functions : Seq [DomainFunc ] = (constructors map encodeAdtConstructorAsDomainFunc(domain)) ++
9292 (constructors flatMap generateDestructorDeclarations(domain)) ++ Seq (generateTagDeclaration(domain))
93- val axioms = (constructors flatMap generateInjectivityAxiom(domain)) ++
93+ val axioms = (constructors flatMap generateInjectivityAxiom(domain)) ++ (constructors flatMap generatePreconditionAxiom(domain)) ++
9494 (constructors map generateTagAxiom(domain)) ++ Seq (generateExclusivityAxiom(domain)(constructors))
9595 val derivingAxioms = if (derivingInfo.contains(getContainsFunctionName))
9696 constructors filter (_.formalArgs.nonEmpty) map generateContainsAxiom(domain, derivingInfo(getContainsFunctionName)._2) else Seq .empty
@@ -136,6 +136,11 @@ class AdtEncoder(val program: Program) extends AdtNameManager {
136136 }
137137 }
138138
139+ private def formalArgsToLocalVars (ac : AdtConstructor ): Seq [LocalVar ] = ac.formalArgs map (lv => lv.typ match {
140+ case a : AdtType => localVarTFromType(encodeAdtTypeAsDomainType(a), Some (lv.name))(ac.pos, ac.info, ac.errT)
141+ case d => localVarTFromType(d, Some (lv.name))(ac.pos, ac.info, ac.errT)
142+ })
143+
139144 /**
140145 * This method encodes an ADT constructor as a domain function
141146 *
@@ -145,7 +150,7 @@ class AdtEncoder(val program: Program) extends AdtNameManager {
145150 */
146151 private def encodeAdtConstructorAsDomainFunc (domain : Domain )(ac : AdtConstructor ): DomainFunc = {
147152 ac match {
148- case AdtConstructor (name, formalArgs) =>
153+ case AdtConstructor (name, formalArgs, _ ) =>
149154 DomainFunc (name, formalArgs, encodeAdtTypeAsDomainType(ac.typ))(ac.pos, ac.info, domain.name, ac.errT)
150155 }
151156 }
@@ -222,7 +227,7 @@ class AdtEncoder(val program: Program) extends AdtNameManager {
222227 * This method generates the corresponding injectivity axiom for an ADT constructor.
223228 *
224229 * axiom {
225- * forall p_1: T_1, ..., p_n: T_n :: {C(p_1, ..., p_n)} p_i == D_Ci (C(p_1, ..., p_n))
230+ * forall p_1: T_1, ..., p_n: T_n :: {C(p_1, ..., p_n)} p_i == D_i (C(p_1, ..., p_n))
226231 * }
227232 *
228233 * where C is the ADT constructor, D_i the destructor for i-th argument of C
@@ -234,12 +239,7 @@ class AdtEncoder(val program: Program) extends AdtNameManager {
234239 private def generateInjectivityAxiom (domain : Domain )(ac : AdtConstructor ): Seq [AnonymousDomainAxiom ] = {
235240 assert(domain.name == ac.adtName, " AdtEncoder: An error in the ADT encoding occurred." )
236241 val localVarDecl = ac.formalArgs.collect { case l : LocalVarDecl => l }
237- val localVars = ac.formalArgs.map { lv =>
238- lv.typ match {
239- case a : AdtType => localVarTFromType(encodeAdtTypeAsDomainType(a), Some (lv.name))(ac.pos, ac.info, ac.errT)
240- case d => localVarTFromType(d, Some (lv.name))(ac.pos, ac.info, ac.errT)
241- }
242- }
242+ val localVars = formalArgsToLocalVars(ac)
243243 assert(localVarDecl.size == localVars.size, " AdtEncoder: An error in the ADT encoding occurred." )
244244
245245 val constructorApp = DomainFuncApp (
@@ -256,11 +256,49 @@ class AdtEncoder(val program: Program) extends AdtNameManager {
256256 defaultTypeVarsFromDomain(domain)
257257 )(ac.pos, ac.info, lv.typ, ac.adtName, ac.errT)
258258 val eq = EqCmp (lv, right)(ac.pos, ac.info, ac.errT)
259- val forall = Forall (localVarDecl, Seq (trigger), eq)(ac.pos, ac.info, ac.errT)
259+ val cond_eq = ac.axiom.map(p => Implies (p, eq)(ac.pos, ac.info, ac.errT)).getOrElse(eq)
260+ val forall = Forall (localVarDecl, Seq (trigger), cond_eq)(ac.pos, ac.info, ac.errT)
260261 AnonymousDomainAxiom (forall)(ac.pos, ac.info, ac.adtName, ac.errT)
261262 }
262263 }
263264
265+ /**
266+ * This method generates the corresponding precondition axiom for an ADT constructor.
267+ *
268+ * axiom {
269+ * forall t: AdtType :: {D_1(t)}...{D_n(t)} pre
270+ * }
271+ *
272+ * where D_i the destructor for i-th argument of C
273+ *
274+ * @param domain The domain the encoded constructor belongs to
275+ * @param ac The adt constructor for which we want to generate the precondition axiom
276+ * @return The precondition axiom if the constructor has a precondition
277+ */
278+ private def generatePreconditionAxiom (domain : Domain )(ac : AdtConstructor ): Option [AnonymousDomainAxiom ] = {
279+ assert(domain.name == ac.adtName, " AdtEncoder: An error in the ADT encoding occurred." )
280+ ac.axiom.map(pre => {
281+ val localVarDecl = localVarTDeclFromType(domainTypeFromDomain(domain))(domain.pos, domain.info, domain.errT)
282+ val localVar = localVarTFromType(domainTypeFromDomain(domain))(domain.pos, domain.info, domain.errT)
283+
284+ val destructorCalls = ac.formalArgs.map { lv =>
285+ DomainFuncApp (
286+ getDestructorName(domain.name, lv.name),
287+ Seq (localVar),
288+ defaultTypeVarsFromDomain(domain)
289+ )(domain.pos, domain.info, lv.typ, domain.name, domain.errT)
290+ }
291+ val localVars = formalArgsToLocalVars(ac)
292+ assert(destructorCalls.size == localVars.size, " AdtEncoder: An error in the ADT encoding occurred." )
293+
294+ val triggers = destructorCalls.map { t => Trigger (Seq (t))(domain.pos, domain.info, domain.errT) }
295+ val pre_sub = pre.replace(localVars.zip(destructorCalls).toMap)
296+ AnonymousDomainAxiom (
297+ Forall (Seq (localVarDecl), triggers, pre_sub)(domain.pos, domain.info, domain.errT)
298+ )(domain.pos, domain.info, domain.name, domain.errT)
299+ })
300+ }
301+
264302 /**
265303 * This method generates the corresponding exclusivity axioms for a sequence of constructors.
266304 *
0 commit comments