Skip to content

Commit bee909f

Browse files
committed
Avoid linear lookups in a Program (fixes #657)
1 parent d4ac4f1 commit bee909f

4 files changed

Lines changed: 30 additions & 18 deletions

File tree

src/main/scala/viper/silver/ast/Program.scala

Lines changed: 26 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,13 @@ import scala.reflect.ClassTag
2121
case class Program(domains: Seq[Domain], fields: Seq[Field], functions: Seq[Function], predicates: Seq[Predicate], methods: Seq[Method], extensions: Seq[ExtensionMember])(val pos: Position = NoPosition, val info: Info = NoInfo, val errT: ErrorTrafo = NoTrafos)
2222
extends Node with DependencyAware with Positioned with Infoed with Scope with TransformableErrors {
2323

24+
lazy val domainsByName: Map[String, Domain] = domains.map(x => (x.name, x)).toMap
25+
lazy val domainFunctionsByName: Map[String, DomainFunc] = domains.flatMap(_.functions).map(x => (x.name, x)).toMap
26+
lazy val fieldsByName: Map[String, Field] = fields.map(x => (x.name, x)).toMap
27+
lazy val functionsByName: Map[String, Function] = functions.map(x => (x.name, x)).toMap
28+
lazy val predicatesByName: Map[String, Predicate] = predicates.map(x => (x.name, x)).toMap
29+
lazy val methodsByName: Map[String, Method] = methods.map(x => (x.name, x)).toMap
30+
2431
val scopedDecls: Seq[Declaration] =
2532
domains ++ fields ++ functions ++ predicates ++ methods ++ extensions ++
2633
domains.flatMap(d => {(d.axioms.filter(_.isInstanceOf[NamedDomainAxiom])).asInstanceOf[Seq[NamedDomainAxiom]] ++ d.functions})
@@ -48,7 +55,7 @@ case class Program(domains: Seq[Domain], fields: Seq[Field], functions: Seq[Func
4855
case None => /* Nothing to do */
4956
case Some(actualBody) =>
5057
for (c@MethodCall(name, args, targets) <- actualBody) {
51-
methods.find(_.name == name) match {
58+
findMethodOptionally(name) match {
5259
case Some(existingMethod) =>
5360
if(!Consistency.areAssignable(existingMethod.formalReturns, targets))
5461
s :+= ConsistencyError(s"Formal returns ${existingMethod.formalReturns} of method $name are not assignable to targets $targets.", c.pos)
@@ -69,8 +76,7 @@ case class Program(domains: Seq[Domain], fields: Seq[Field], functions: Seq[Func
6976
var errors = Seq.empty[ConsistencyError]
7077

7178
def check(loc: PredicateAccess, pos: Position): Unit = {
72-
predicates
73-
.find(_.name == loc.predicateName)
79+
findPredicateOptionally(loc.predicateName)
7480
.foreach(predicate => {
7581
if (predicate.body.isEmpty)
7682
errors :+= ConsistencyError(s"Cannot unfold $loc because ${loc.predicateName} is abstract.", pos)
@@ -93,7 +99,7 @@ case class Program(domains: Seq[Domain], fields: Seq[Field], functions: Seq[Func
9399
var s = Seq.empty[ConsistencyError]
94100

95101
for (funcApp@FuncApp(name, args) <- this) {
96-
this.findFunctionOptionally(name) match {
102+
findFunctionOptionally(name) match {
97103
case None => // Consistency error already reported by checkIdentifiers
98104
case Some(funcDef) => {
99105
if (!Consistency.areAssignable(args, funcDef.formalArgs)) {
@@ -121,7 +127,7 @@ case class Program(domains: Seq[Domain], fields: Seq[Field], functions: Seq[Func
121127
var s = Seq.empty[ConsistencyError]
122128

123129
for (predAcc@PredicateAccess(args, name) <- this) {
124-
this.findPredicateOptionally(name) match {
130+
findPredicateOptionally(name) match {
125131
case None => // Consistency error already reported by checkIdentifiers
126132
case Some(predDef) => {
127133
if (!Consistency.areAssignable(args, predDef.formalArgs)) {
@@ -145,7 +151,7 @@ case class Program(domains: Seq[Domain], fields: Seq[Field], functions: Seq[Func
145151
var s = Seq.empty[ConsistencyError]
146152

147153
for (funcApp@DomainFuncApp(name, args, typVarMap) <- this) {
148-
this.findDomainFunctionOptionally(name) match {
154+
findDomainFunctionOptionally(name) match {
149155
case None => s :+= ConsistencyError(s"No domain function named $name found in the program.", funcApp.pos)
150156
case Some(funcDef) => {
151157
if (!Consistency.areAssignable(args, funcDef.formalArgs map {
@@ -264,21 +270,25 @@ case class Program(domains: Seq[Domain], fields: Seq[Field], functions: Seq[Func
264270

265271
lazy val members: Seq[Member with Serializable] = domains ++ fields ++ functions ++ predicates ++ methods
266272

273+
def findFieldOptionally(name: String): Option[Field] = this.fieldsByName.get(name)
274+
267275
def findField(name: String): Field = {
268-
this.fields.find(_.name == name) match {
276+
findFieldOptionally(name) match {
269277
case Some(f) => f
270278
case None => sys.error("Field name " + name + " not found in program.")
271279
}
272280
}
273281

282+
def findMethodOptionally(name: String): Option[Method] = this.methodsByName.get(name)
283+
274284
def findMethod(name: String): Method = {
275-
this.methods.find(_.name == name) match {
285+
findMethodOptionally(name) match {
276286
case Some(m) => m
277287
case None => sys.error("Method name " + name + " not found in program.")
278288
}
279289
}
280290

281-
def findFunctionOptionally(name: String): Option[Function] = this.functions.find(_.name == name)
291+
def findFunctionOptionally(name: String): Option[Function] = this.functionsByName.get(name)
282292

283293
def findFunction(name: String): Function = {
284294
findFunctionOptionally(name) match {
@@ -287,23 +297,25 @@ case class Program(domains: Seq[Domain], fields: Seq[Field], functions: Seq[Func
287297
}
288298
}
289299

290-
def findPredicateOptionally(name: String): Option[Predicate] = this.predicates.find(_.name == name)
300+
def findPredicateOptionally(name: String): Option[Predicate] = this.predicatesByName.get(name)
291301

292302
def findPredicate(name: String): Predicate = {
293-
this.predicates.find(_.name == name) match {
303+
findPredicateOptionally(name) match {
294304
case Some(p) => p
295305
case None => sys.error("Predicate name " + name + " not found in program.")
296306
}
297307
}
298308

309+
def findDomainOptionally(name: String): Option[Domain] = this.domainsByName.get(name)
310+
299311
def findDomain(name: String): Domain = {
300-
this.domains.find(_.name == name) match {
312+
findDomainOptionally(name) match {
301313
case Some(d) => d
302314
case None => sys.error("Domain name " + name + " not found in program.")
303315
}
304316
}
305317

306-
def findDomainFunctionOptionally(name: String): Option[DomainFunc] = this.domains.flatMap(_.functions).find(_.name == name)
318+
def findDomainFunctionOptionally(name: String): Option[DomainFunc] = this.domainFunctionsByName.get(name)
307319

308320
def findDomainFunction(name: String): DomainFunc = {
309321
findDomainFunctionOptionally(name) match {
@@ -583,7 +595,7 @@ object Substitution{
583595
}
584596
/** Domain function which is not a binary or unary operator. */
585597
case class DomainFunc(name: String, formalArgs: Seq[AnyLocalVarDecl], typ: Type, unique: Boolean = false, interpretation: Option[String] = None)
586-
(val pos: Position = NoPosition, val info: Info = NoInfo,val domainName : String, val errT: ErrorTrafo = NoTrafos)
598+
(val pos: Position = NoPosition, val info: Info = NoInfo, val domainName: String, val errT: ErrorTrafo = NoTrafos)
587599
extends AbstractDomainFunc with DomainMember with Declaration {
588600
override lazy val check : Seq[ConsistencyError] =
589601
if (unique && formalArgs.nonEmpty) Seq(ConsistencyError("Only constants, i.e. nullary domain functions can be unique.", pos)) else Seq()

src/main/scala/viper/silver/ast/utility/Consistency.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -357,7 +357,7 @@ object Consistency {
357357
c
358358

359359
case dt: DomainType =>
360-
c.program.domains.find(_.name == dt.domainName) match {
360+
c.program.findDomainOptionally(dt.domainName) match {
361361
case None =>
362362
s :+= ConsistencyError(s"DomainType references non-existent domain ${dt.domainName}.", NoPosition)
363363
c
@@ -368,7 +368,7 @@ object Consistency {
368368
}
369369

370370
case bt: BackendType =>
371-
c.program.domains.find(_.name == bt.viperName) match {
371+
c.program.findDomainOptionally(bt.viperName) match {
372372
case None =>
373373
s :+= ConsistencyError(s"BackendType references non-existent domain ${bt.viperName}.", NoPosition)
374374
c

src/main/scala/viper/silver/plugin/standard/predicateinstance/PredicateInstancePlugin.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ class PredicateInstancePlugin(@unused reporter: viper.silver.reporter.Reporter,
5858
* (to the respective predicate instance functions)
5959
*/
6060
override def beforeVerify(input: Program): Program = {
61-
val PredicateInstanceDomain: Option[Domain] = input.domains.find(_.name == "PredicateInstance")
61+
val PredicateInstanceDomain: Option[Domain] = input.findDomainOptionally("PredicateInstance")
6262

6363
// list of all created predicate instance functions
6464
var createdPIFunctions = ListMap[String, Function]()

src/main/scala/viper/silver/plugin/standard/termination/transformation/MethodCheck.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ import viper.silver.verifier.errors.AssertFailed
1919
trait MethodCheck extends ProgramManager with DecreasesCheck with NestedPredicates with ErrorReporter {
2020

2121
private def getMethodDecreasesSpecification(method: String): DecreasesSpecification = {
22-
program.methods.find(_.name == method) match {
22+
program.findMethod(method) match {
2323
case Some(f) => DecreasesSpecification.fromNode(f)
2424
case None => DecreasesSpecification()
2525
}

0 commit comments

Comments
 (0)