|
| 1 | +// This Source Code Form is subject to the terms of the Mozilla Public |
| 2 | +// License, v. 2.0. If a copy of the MPL was not distributed with this |
| 3 | +// file, You can obtain one at http://mozilla.org/MPL/2.0/. |
| 4 | +// |
| 5 | +// Copyright (c) 2011-2022 ETH Zurich. |
| 6 | + |
| 7 | +package viper.silver.plugin.standard.adt |
| 8 | + |
| 9 | +import viper.silver.ast._ |
| 10 | +import viper.silver.ast.pretty.FastPrettyPrinter.{ContOps, braces, brackets, char, defaultIndent, line, nest, nil, parens, show, showType, showVars, space, ssep, text} |
| 11 | +import viper.silver.ast.pretty.PrettyPrintPrimitives |
| 12 | +import viper.silver.ast.utility.Consistency |
| 13 | +import viper.silver.verifier.{ConsistencyError, Failure, VerificationResult} |
| 14 | + |
| 15 | +/** |
| 16 | + * This class represents a user-defined ADT. |
| 17 | + * |
| 18 | + * @param name name of the ADT |
| 19 | + * @param constructors sequence of corresponding constructors |
| 20 | + * @param typVars sequence of type variables (generics) |
| 21 | + * @param derivingInfo a map that maps identifiers of derivable functions to a tuple containing an optional type param and a set of excluded constructor argument identifiers |
| 22 | + */ |
| 23 | +case class Adt(name: String, constructors: Seq[AdtConstructor], typVars: Seq[TypeVar] = Nil, derivingInfo: Map[String, (Option[Type], Set[String])] = Map.empty) |
| 24 | + (val pos: Position = NoPosition, val info: Info = NoInfo, val errT: ErrorTrafo = NoTrafos) extends ExtensionMember { |
| 25 | + val scopedDecls: Seq[Declaration] = Seq() |
| 26 | + |
| 27 | + override def extensionSubnodes: Seq[Node] = constructors ++ typVars ++ derivingInfo.map(_._2._1).collect { case Some(v) => v } |
| 28 | + |
| 29 | + override def prettyPrint: PrettyPrintPrimitives#Cont = { |
| 30 | + |
| 31 | + def showDerivingInfo(di: (String, (Option[Type], Set[String]))): PrettyPrintPrimitives#Cont = { |
| 32 | + val (func, (param, blocklist)) = di |
| 33 | + text(func) <> (if (param.isEmpty) nil else text("[") <> showType(param.get) <> space <> "]") <> |
| 34 | + space <> (if (blocklist.isEmpty) nil else text("without") <> space <> ssep(blocklist.toSeq map text, char(',') <> space)) |
| 35 | + } |
| 36 | + |
| 37 | + text("adt") <+> name <> |
| 38 | + (if (typVars.isEmpty) nil else text("[") <> ssep(typVars map show, char(',') <> space) <> "]") <+> |
| 39 | + braces(nest(defaultIndent, |
| 40 | + line <> line <> |
| 41 | + ssep(constructors map show, line <> line) |
| 42 | + ) <> line) <+> |
| 43 | + (if (derivingInfo.isEmpty) nil else text("derives") <+> |
| 44 | + braces(nest(defaultIndent, |
| 45 | + line <> line <> |
| 46 | + ssep(derivingInfo.toSeq map showDerivingInfo, line <> line) |
| 47 | + ) <> line) |
| 48 | + ) |
| 49 | + } |
| 50 | +} |
| 51 | + |
| 52 | +/** |
| 53 | + * This class represents an ADT constructor. See also the companion object below, which allows passing a |
| 54 | + * Adt - this should be used in general for creation (so that typ is guaranteed to |
| 55 | + * be set correctly) |
| 56 | + * |
| 57 | + * @param name name of the ADT constructor |
| 58 | + * @param formalArgs sequence of arguments of the constructor |
| 59 | + * @param typ the return type of the constructor |
| 60 | + * @param adtName the name corresponding of the corresponding ADT |
| 61 | + */ |
| 62 | +case class AdtConstructor(name: String, formalArgs: Seq[LocalVarDecl]) |
| 63 | + (val pos: Position, val info: Info, val typ: AdtType, val adtName: String, val errT: ErrorTrafo) |
| 64 | + extends ExtensionMember { |
| 65 | + |
| 66 | + val scopedDecls: Seq[Declaration] = formalArgs |
| 67 | + |
| 68 | + override def getMetadata: Seq[Any] = { |
| 69 | + Seq(pos, info, errT) |
| 70 | + } |
| 71 | + |
| 72 | + override def extensionSubnodes: Seq[Node] = formalArgs |
| 73 | + |
| 74 | + override def prettyPrint: PrettyPrintPrimitives#Cont = text(name) <> parens(showVars(formalArgs)) |
| 75 | + |
| 76 | + override def withChildren(children: Seq[Any], pos: Option[(Position, Position)], forceRewrite: Boolean): this.type = { |
| 77 | + if (!forceRewrite && this.children == children && pos.isEmpty) |
| 78 | + this |
| 79 | + else { |
| 80 | + assert(children.length == 2, s"AdtConstructor : expected length 2 but got ${children.length}") |
| 81 | + val first = children.head.asInstanceOf[String] |
| 82 | + val second = children.tail.head.asInstanceOf[Seq[LocalVarDecl]] |
| 83 | + AdtConstructor(first, second)(this.pos, this.info, this.typ, this.adtName, this.errT).asInstanceOf[this.type] |
| 84 | + } |
| 85 | + |
| 86 | + } |
| 87 | +} |
| 88 | + |
| 89 | +object AdtConstructor { |
| 90 | + def apply(adt: Adt, name: String, formalArgs: Seq[LocalVarDecl]) |
| 91 | + (pos: Position = NoPosition, info: Info = NoInfo, errT: ErrorTrafo = NoTrafos): AdtConstructor = { |
| 92 | + AdtConstructor(name, formalArgs)(pos, info, AdtType(adt, (adt.typVars zip adt.typVars).toMap), adt.name, errT) |
| 93 | + } |
| 94 | +} |
| 95 | + |
| 96 | +/** |
| 97 | + * This class represents an user-defined ADT type. See also the companion object below, which allows passing a |
| 98 | + * Adt - this should be used in general for creation (so that typeParameters is guaranteed to |
| 99 | + * be set correctly) |
| 100 | + * |
| 101 | + * @param adtName The name of the underlying adt. |
| 102 | + * @param partialTypVarsMap Maps type parameters to (possibly concrete) types. May not map all |
| 103 | + * type parameters, may even be empty. |
| 104 | + * @param typeParameters The type variables of the ADT type. |
| 105 | + */ |
| 106 | +case class AdtType(adtName: String, partialTypVarsMap: Map[TypeVar, Type]) |
| 107 | + (val typeParameters: Seq[TypeVar]) extends ExtensionType { |
| 108 | + |
| 109 | + override lazy val check: Seq[ConsistencyError] = if (!(typeParameters.toSet == typVarsMap.keys.toSet)) { |
| 110 | + Seq(ConsistencyError(s"${typeParameters.toSet} doesn't equal ${typVarsMap.keys.toSet}", NoPosition)) |
| 111 | + } else Seq() |
| 112 | + |
| 113 | + /** |
| 114 | + * Map each type parameter `A` to `partialTypVarsMap(A)`, if defined, otherwise to `A` itself. |
| 115 | + * `typVarsMap` thus contains a mapping for each type parameter. |
| 116 | + */ |
| 117 | + val typVarsMap: Map[TypeVar, Type] = |
| 118 | + typeParameters.map(tp => tp -> partialTypVarsMap.getOrElse(tp, tp)).to(implicitly) |
| 119 | + |
| 120 | + /** |
| 121 | + * Takes a mapping of type variables to types and substitutes all |
| 122 | + * occurrences of those type variables with the corresponding type. |
| 123 | + */ |
| 124 | + override def substitute(newTypVarsMap: Map[TypeVar, Type]): Type = { |
| 125 | + assert(typVarsMap.keys.toSet equals this.typeParameters.toSet) |
| 126 | + val newTypeMap = typVarsMap.map(kv => kv._1 -> kv._2.substitute(newTypVarsMap)) |
| 127 | + AdtType(adtName, newTypeMap)(typeParameters) |
| 128 | + } |
| 129 | + |
| 130 | + /** Is this a concrete type (i.e. no uninstantiated type variables)? */ |
| 131 | + override def isConcrete: Boolean = typVarsMap.values.forall(_.isConcrete) |
| 132 | + |
| 133 | + override def prettyPrint: PrettyPrintPrimitives#Cont = { |
| 134 | + val typArgs = typeParameters map (t => show(typVarsMap.getOrElse(t, t))) |
| 135 | + text(adtName) <> (if (typArgs.isEmpty) nil else brackets(ssep(typArgs, char(',') <> space))) |
| 136 | + } |
| 137 | + |
| 138 | + override def withChildren(children: Seq[Any], pos: Option[(Position, Position)], forceRewrite: Boolean): this.type = { |
| 139 | + if (!forceRewrite && this.children == children && pos.isEmpty) |
| 140 | + this |
| 141 | + else { |
| 142 | + assert(children.length == 2, s"AdtType : expected length 2 but got ${children.length}") |
| 143 | + val first = children.head.asInstanceOf[String] |
| 144 | + val second = children.tail.head.asInstanceOf[Map[TypeVar, Type]] |
| 145 | + AdtType(first, second)(this.typeParameters).asInstanceOf[this.type] |
| 146 | + } |
| 147 | + } |
| 148 | + |
| 149 | +} |
| 150 | + |
| 151 | +object AdtType { |
| 152 | + def apply(adt: Adt, typVarsMap: Map[TypeVar, Type]): AdtType = |
| 153 | + AdtType(adt.name, typVarsMap)(adt.typVars) |
| 154 | +} |
| 155 | + |
| 156 | + |
| 157 | +/** |
| 158 | + * This class represents a user-defined adt constructor application. See also the companion object below, which allows passing a |
| 159 | + * Adt constructor - this should be used in general for creation (so that typ is guaranteed to |
| 160 | + * be set correctly) |
| 161 | + * |
| 162 | + * @param name The name of the ADT constructor |
| 163 | + * @param args A sequence of expressions passed as arguments to the constructor |
| 164 | + * @param typVarMap Maps type parameters to (possibly concrete) types. May not map all |
| 165 | + * type parameters, may even be empty. |
| 166 | + * @param typ The return type of the constructor |
| 167 | + * @param adtName The corresponding ADT name |
| 168 | + */ |
| 169 | +case class AdtConstructorApp(name: String, args: Seq[Exp], typVarMap: Map[TypeVar, Type]) |
| 170 | + (val pos: Position, val info: Info, override val typ: Type, val adtName: String, val errT: ErrorTrafo) |
| 171 | + extends ExtensionExp { |
| 172 | + override lazy val check: Seq[ConsistencyError] = args.flatMap(Consistency.checkPure) |
| 173 | + |
| 174 | + override def prettyPrint: PrettyPrintPrimitives#Cont = { |
| 175 | + if (typVarMap.nonEmpty) |
| 176 | + // Type may be under-constrained, so to be safe we explicitly print out the type. |
| 177 | + parens(text(name) <> parens(ssep(args map show, char(',') <> space)) <> char(':') <+> show(typ)) |
| 178 | + else |
| 179 | + text(name) <> parens(ssep(args map show, char(',') <> space)) |
| 180 | + } |
| 181 | + |
| 182 | + override def extensionIsPure: Boolean = true |
| 183 | + |
| 184 | + override def extensionSubnodes: Seq[Node] = args ++ typVarMap.keys ++ typVarMap.values |
| 185 | + |
| 186 | + override def verifyExtExp(): VerificationResult = { |
| 187 | + assert(assertion = false, "AdtConstructorApp: verifyExtExp has not been implemented.") |
| 188 | + Failure(Seq(ConsistencyError("AdtConstructorApp: verifyExtExp has not been implemented.", pos))) |
| 189 | + } |
| 190 | + |
| 191 | + override def withChildren(children: Seq[Any], pos: Option[(Position, Position)], forceRewrite: Boolean): AdtConstructorApp.this.type = { |
| 192 | + if (!forceRewrite && this.children == children && pos.isEmpty) |
| 193 | + this |
| 194 | + else { |
| 195 | + assert(children.length == 3, s"AdtConstructorApp : expected length 3 but got ${children.length}") |
| 196 | + val first = children.head.asInstanceOf[String] |
| 197 | + val second = children(1).asInstanceOf[Seq[Exp]] |
| 198 | + val third = children(2).asInstanceOf[Map[TypeVar, Type]] |
| 199 | + AdtConstructorApp(first, second, third)(this.pos, this.info, this.typ, this.adtName, this.errT).asInstanceOf[this.type] |
| 200 | + } |
| 201 | + } |
| 202 | +} |
| 203 | + |
| 204 | +object AdtConstructorApp { |
| 205 | + def apply(constructor: AdtConstructor, args: Seq[Exp], typVarMap: Map[TypeVar, Type]) |
| 206 | + (pos: Position = NoPosition, info: Info = NoInfo, errT: ErrorTrafo = NoTrafos): AdtConstructorApp = |
| 207 | + AdtConstructorApp(constructor.name, args, typVarMap)(pos, info, constructor.typ.substitute(typVarMap), constructor.adtName, errT) |
| 208 | +} |
| 209 | + |
| 210 | +/** |
| 211 | + * This class represents an adt destructor application. See also the companion object below, which allows passing a |
| 212 | + * Adt - this should be used in general for creation (so that typ is guaranteed to |
| 213 | + * be set correctly) |
| 214 | + * |
| 215 | + * @param name The name of the argument of an ADT constructor the destructor corresponds to |
| 216 | + * @param rcv An expression on with the the destructor is applied |
| 217 | + * @param typVarMap Maps type parameters to (possibly concrete) types. May not map all |
| 218 | + * type parameters, may even be empty. |
| 219 | + * @param typ The return type of the destructor |
| 220 | + * @param adtName The corresponding ADT name |
| 221 | + */ |
| 222 | +case class AdtDestructorApp(name: String, rcv: Exp, typVarMap: Map[TypeVar, Type]) |
| 223 | + (val pos: Position, val info: Info, override val typ: Type, val adtName: String, val errT: ErrorTrafo) extends ExtensionExp { |
| 224 | + |
| 225 | + override lazy val check: Seq[ConsistencyError] = Consistency.checkPure(rcv) |
| 226 | + |
| 227 | + override def prettyPrint: PrettyPrintPrimitives#Cont = show(rcv) <> "." <> name |
| 228 | + |
| 229 | + override def extensionIsPure: Boolean = true |
| 230 | + |
| 231 | + override def extensionSubnodes: Seq[Node] = Seq(rcv) ++ typVarMap.keys ++ typVarMap.values |
| 232 | + |
| 233 | + override def verifyExtExp(): VerificationResult = { |
| 234 | + assert(assertion = false, "AdtDestructorApp: verifyExtExp has not been implemented.") |
| 235 | + Failure(Seq(ConsistencyError("AdtDestructorApp: verifyExtExp has not been implemented.", pos))) |
| 236 | + } |
| 237 | + |
| 238 | + override def withChildren(children: Seq[Any], pos: Option[(Position, Position)], forceRewrite: Boolean): this.type = { |
| 239 | + if (!forceRewrite && this.children == children && pos.isEmpty) |
| 240 | + this |
| 241 | + else { |
| 242 | + assert(children.length == 3, s"AdtDestructorApp : expected length 3 but got ${children.length}") |
| 243 | + val first = children.head.asInstanceOf[String] |
| 244 | + val second = children(1).asInstanceOf[Exp] |
| 245 | + val third = children(2).asInstanceOf[Map[TypeVar, Type]] |
| 246 | + AdtDestructorApp(first, second, third)(this.pos, this.info, this.typ, this.adtName, this.errT).asInstanceOf[this.type] |
| 247 | + } |
| 248 | + } |
| 249 | +} |
| 250 | + |
| 251 | +object AdtDestructorApp { |
| 252 | + def apply(adt: Adt, name: String, rcv: Exp, typVarMap: Map[TypeVar, Type]) |
| 253 | + (pos: Position = NoPosition, info: Info = NoInfo, errT: ErrorTrafo = NoTrafos): AdtDestructorApp = { |
| 254 | + val matchingConstructors = adt.constructors flatMap (c => c.formalArgs.filter { lv => lv.name == name }) |
| 255 | + assert(matchingConstructors.length == 1, s"AdtDestructorApp : expected length 1 but got ${matchingConstructors.length}") |
| 256 | + val typ = matchingConstructors.head.typ |
| 257 | + AdtDestructorApp(name, rcv, typVarMap)(pos, info, typ.substitute(typVarMap), adt.name, errT) |
| 258 | + } |
| 259 | +} |
| 260 | + |
| 261 | +/** |
| 262 | + * This class represents an adt discriminator application. See also the companion object below, which allows passing a |
| 263 | + * Adt - this should be used in general for creation (so that adtName is guaranteed to |
| 264 | + * be set correctly) |
| 265 | + * |
| 266 | + * @param name The name of the argument of an ADT constructor the destructor corresponds to |
| 267 | + * @param rcv An expression on with the the destructor is applied |
| 268 | + * @param typVarMap Maps type parameters to (possibly concrete) types. May not map all |
| 269 | + * type parameters, may even be empty. |
| 270 | + * @param adtName The corresponding ADT name |
| 271 | + */ |
| 272 | +case class AdtDiscriminatorApp(name: String, rcv: Exp, typVarMap: Map[TypeVar, Type]) |
| 273 | + (val pos: Position, val info: Info, val adtName: String, val errT: ErrorTrafo) extends ExtensionExp { |
| 274 | + |
| 275 | + override lazy val check: Seq[ConsistencyError] = Consistency.checkPure(rcv) |
| 276 | + |
| 277 | + override def typ: Type = Bool |
| 278 | + |
| 279 | + override def prettyPrint: PrettyPrintPrimitives#Cont = show(rcv) <> "." <> name <> "?" |
| 280 | + |
| 281 | + override def extensionIsPure: Boolean = true |
| 282 | + |
| 283 | + override def extensionSubnodes: Seq[Node] = Seq(rcv) ++ typVarMap.keys ++ typVarMap.values |
| 284 | + |
| 285 | + override def verifyExtExp(): VerificationResult = { |
| 286 | + assert(assertion = false, "AdtDiscriminatorApp: verifyExtExp has not been implemented.") |
| 287 | + Failure(Seq(ConsistencyError("AdtDiscriminatorApp: verifyExtExp has not been implemented.", pos))) |
| 288 | + } |
| 289 | + |
| 290 | + override def withChildren(children: Seq[Any], pos: Option[(Position, Position)], forceRewrite: Boolean): this.type = { |
| 291 | + if (!forceRewrite && this.children == children && pos.isEmpty) |
| 292 | + this |
| 293 | + else { |
| 294 | + assert(children.length == 3, s"AdtDestructorApp : expected length 3 but got ${children.length}") |
| 295 | + val first = children.head.asInstanceOf[String] |
| 296 | + val second = children(1).asInstanceOf[Exp] |
| 297 | + val third = children(2).asInstanceOf[Map[TypeVar, Type]] |
| 298 | + AdtDiscriminatorApp(first, second, third)(this.pos, this.info, this.adtName, this.errT).asInstanceOf[this.type] |
| 299 | + } |
| 300 | + } |
| 301 | + |
| 302 | +} |
| 303 | + |
| 304 | +object AdtDiscriminatorApp { |
| 305 | + def apply(adt: Adt, name: String, rcv: Exp, typVarMap: Map[TypeVar, Type]) |
| 306 | + (pos: Position = NoPosition, info: Info = NoInfo, errT: ErrorTrafo = NoTrafos): AdtDiscriminatorApp = { |
| 307 | + AdtDiscriminatorApp(name, rcv, typVarMap)(pos, info, adt.name, errT) |
| 308 | + } |
| 309 | +} |
| 310 | + |
0 commit comments