forked from epfl-lara/inox
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Definitions.scala
607 lines (478 loc) · 24 KB
/
Definitions.scala
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
/* Copyright 2009-2018 EPFL, Lausanne */
package inox
package ast
import inox.parsing.Interpolator
import inox.transformers._
import inox.utils._
import scala.collection.concurrent.{Map => ConcurrentMap}
import scala.jdk.CollectionConverters._
import scala.util.Try
/** Provides types that describe Inox definitions. */
trait Definitions { self: Trees =>
/** The base trait for Inox definitions */
trait Definition extends Tree {
def id: Identifier
def flags: Seq[Flag]
override def equals(that: Any): Boolean = that match {
case d: Definition => id == d.id
case _=> false
}
override def hashCode = id.hashCode
}
abstract class LookupException(id: Identifier, what: String)
extends Exception("Lookup failed for " + what + " with symbol `" + id.uniqueName + "`")
case class FunctionLookupException(id: Identifier) extends LookupException(id, "function")
case class ADTLookupException(id: Identifier) extends LookupException(id, "adt")
case class NotWellFormedException(d: Definition, info: Option[String] = None)
extends Exception(s"Not well formed definition $d" + (info map { i => s" \n\tbecause $i" } getOrElse ""))
/** Common super-type for [[ValDef]] and [[Expressions.Variable Variable]].
*
* Both types share much in common and being able to reason about them
* in a uniform manner can be useful in certain cases.
*/
protected[ast] trait VariableSymbol extends Tree with Typed {
def id: Identifier
def tpe: Type
def flags: Seq[Flag]
def getType(implicit s: Symbols): Type = tpe.getType
def to[A <: VariableSymbol](implicit ev: VariableConverter[A]): A = ev.convert(this)
override def equals(that: Any): Boolean = that match {
case vs: VariableSymbol => id == vs.id && tpe == vs.tpe && flags == vs.flags
case _ => false
}
override def hashCode: Int = 61 * id.hashCode + 31 * tpe.hashCode + flags.hashCode
}
implicit def variableSymbolOrdering[VS <: VariableSymbol]: Ordering[VS] =
Ordering.by(e => e.id)
abstract class VariableConverter[B <: VariableSymbol] {
def convert(a: VariableSymbol): B
}
implicit def convertToVal = new VariableConverter[ValDef] {
def convert(vs: VariableSymbol): ValDef = vs match {
case v: ValDef => v
case _ => ValDef(vs.id, vs.tpe, vs.flags).copiedFrom(vs)
}
}
implicit def convertToVariable = new VariableConverter[Variable] {
def convert(vs: VariableSymbol): Variable = vs match {
case v: Variable => v
case _ => Variable(vs.id, vs.tpe, vs.flags).copiedFrom(vs)
}
}
/**
* A ValDef declares a formal parameter (with symbol [[id]]) to be of a certain type.
*/
sealed class ValDef(v: Variable) extends Definition with VariableSymbol {
@inline def id = v.id
@inline def tpe = v.tpe
@inline def flags = v.flags
override def setPos(pos: Position): ValDef.this.type = {
v.setPos(pos)
super.setPos(pos)
}
/** Transform this [[ValDef]] into a [[Expressions.Variable Variable]] */
@inline def toVariable: Variable = v.copy().copiedFrom(v)
@inline def freshen: ValDef = new ValDef(v.freshen).copiedFrom(this)
override def equals(that: Any): Boolean = super[VariableSymbol].equals(that)
override def hashCode: Int = super[VariableSymbol].hashCode
override def toString: String = s"ValDef($id, $tpe, $flags)"
def copy(id: Identifier = id, tpe: Type = tpe, flags: Seq[Flag] = flags): ValDef =
new ValDef(v.copy(id = id, tpe = tpe, flags = flags)).copiedFrom(this)
}
object ValDef {
def fresh(name: String, tpe: Type, alwaysShowUniqueID: Boolean = false) =
ValDef(FreshIdentifier(name, alwaysShowUniqueID), tpe)
def apply(id: Identifier, tpe: Type, flags: Seq[Flag] = Seq.empty) = new ValDef(Variable(id, tpe, flags))
def unapply(vd: ValDef): Option[(Identifier, Type, Seq[Flag])] = Some((vd.id, vd.tpe, vd.flags))
}
type Symbols >: Null <: AbstractSymbols
val NoSymbols: Symbols
/** Provides the class and function definitions of a program and lookups on them */
trait AbstractSymbols
extends Printable
with TypeOps
with SymbolOps
with CallGraph
with DependencyGraph { self0: Symbols =>
val sorts: Map[Identifier, ADTSort]
val functions: Map[Identifier, FunDef]
@inline def constructors: Map[Identifier, ADTConstructor] = _constructors.get
private[this] val _constructors: Lazy[Map[Identifier, ADTConstructor]] =
Lazy(sorts.values.flatMap(_.constructors.map(cons => cons.id -> cons)).toMap)
protected val trees: self.type = self
protected val symbols: this.type = this
type Semantics = inox.Semantics {
val trees: self0.trees.type
val symbols: self0.symbols.type
}
// @nv: this is a hack to reinject `this` into the set of implicits
// in scope when using the pattern:
// {{{
// implicit val symbols: Symbols
// import symbols._
// }}}
// which seems to remove `symbols` from the set of current implicits
// for some mysterious reason.
implicit def implicitSymbols: this.type = this
private[this] val typedSortCache: ConcurrentMap[(Identifier, Seq[Type]), Option[TypedADTSort]] =
new java.util.concurrent.ConcurrentHashMap[(Identifier, Seq[Type]), Option[TypedADTSort]].asScala
def lookupSort(id: Identifier): Option[ADTSort] = sorts.get(id)
def lookupSort(id: Identifier, tps: Seq[Type]): Option[TypedADTSort] = {
typedSortCache.getOrElse(id -> tps, {
val res = lookupSort(id).map(TypedADTSort(_, tps))
typedSortCache(id -> tps) = res
res
})
}
def getSort(id: Identifier): ADTSort =
lookupSort(id).getOrElse(throw ADTLookupException(id))
def getSort(id: Identifier, tps: Seq[Type]): TypedADTSort =
lookupSort(id, tps).getOrElse(throw ADTLookupException(id))
private[this] val typedConstructorCache: ConcurrentMap[(Identifier, Seq[Type]), Option[TypedADTConstructor]] =
new java.util.concurrent.ConcurrentHashMap[(Identifier, Seq[Type]), Option[TypedADTConstructor]].asScala
def lookupConstructor(id: Identifier): Option[ADTConstructor] = constructors.get(id)
def lookupConstructor(id: Identifier, tps: Seq[Type]): Option[TypedADTConstructor] =
typedConstructorCache.getOrElse(id -> tps, {
val res = constructors.get(id).flatMap { cons =>
lookupSort(cons.sort, tps).flatMap(_.constructors.collectFirst {
case tcons if tcons.id == id => tcons
})
}
typedConstructorCache(id -> tps) = res
res
})
def getConstructor(id: Identifier): ADTConstructor =
lookupConstructor(id).getOrElse(throw ADTLookupException(id))
def getConstructor(id: Identifier, tps: Seq[Type]): TypedADTConstructor =
lookupConstructor(id, tps).getOrElse(throw ADTLookupException(id))
private[this] val typedFunctionCache: ConcurrentMap[(Identifier, Seq[Type]), Option[TypedFunDef]] =
new java.util.concurrent.ConcurrentHashMap[(Identifier, Seq[Type]), Option[TypedFunDef]].asScala
def lookupFunction(id: Identifier): Option[FunDef] = functions.get(id)
def lookupFunction(id: Identifier, tps: Seq[Type]): Option[TypedFunDef] =
typedFunctionCache.getOrElse(id -> tps, {
val res = lookupFunction(id).map(TypedFunDef(_, tps))
typedFunctionCache(id -> tps) = res
res
})
def getFunction(id: Identifier): FunDef =
lookupFunction(id).getOrElse(throw FunctionLookupException(id))
def getFunction(id: Identifier, tps: Seq[Type]): TypedFunDef =
lookupFunction(id, tps).getOrElse(throw FunctionLookupException(id))
override def toString: String = asString(PrinterOptions(symbols = Some(this)))
override def asString(implicit opts: PrinterOptions): String = {
sorts.map(p => prettyPrint(p._2, opts)).mkString("\n\n") +
"\n\n-----------\n\n" +
functions.map(p => prettyPrint(p._2, opts)).mkString("\n\n")
}
def transform(t: DefinitionTransformer { val s: self.type }): t.t.Symbols = {
SymbolTransformer(t).transform(this)
}
/** Makes sure these symbols pass a certain number of well-formedness checks, such as
* - function definition bodies satisfy the declared return types
* - adt sorts and constructors point to each other correctly
* - each adt type has at least one instance
* - adt type parameter flags match between children and parents
* - every variable is available in the scope of its usage
*/
@inline def ensureWellFormed: Unit = _tryWF.get.get
private[this] val _tryWF: Lazy[Try[Unit]] = Lazy(Try(ensureWellFormedSymbols))
protected def ensureWellFormedSymbols: Unit = {
for ((_, fd) <- functions) ensureWellFormedFunction(fd)
for ((_, sort) <- sorts) ensureWellFormedSort(sort)
}
protected def ensureWellFormedFunction(fd: FunDef) = {
typeCheck(fd.fullBody, fd.getType)
if (!fd.getType.isTyped) throw NotWellFormedException(fd)
if (!(fd.params forall (_.isTyped))) throw NotWellFormedException(fd)
val unbound: Seq[Variable] = collectWithPC(fd.fullBody, Path.empty withBounds fd.params) {
case (v: Variable, path) if !(path isBound v) => v
}
if (unbound.nonEmpty) {
throw NotWellFormedException(fd, Some("Unknown variables: " + (unbound map { _.id.uniqueName } mkString ", ")))
}
}
protected def ensureWellFormedSort(sort: ADTSort) = {
if (!sort.isWellFormed) throw NotWellFormedException(sort)
if (!(sort.constructors forall (cons => cons.sort == sort.id))) throw NotWellFormedException(sort)
if (!(sort.constructors forall (_.fields forall (_.isTyped)))) throw NotWellFormedException(sort)
if (sort.constructors.flatMap(_.fields).groupBy(_.id).exists(_._2.size > 1)) throw NotWellFormedException(sort)
}
override def equals(that: Any): Boolean = that match {
case sym: AbstractSymbols => functions == sym.functions && sorts == sym.sorts
case _ => false
}
override def hashCode: Int = functions.hashCode * 61 + sorts.hashCode
def withFunctions(functions: Seq[FunDef]): Symbols
def withSorts(sorts: Seq[ADTSort]): Symbols
}
sealed class TypeParameterDef(val tp: TypeParameter) extends Definition {
copiedFrom(tp)
@inline def id = tp.id
@inline def flags = tp.flags
@inline def freshen = new TypeParameterDef(tp.freshen)
override def equals(that: Any): Boolean = that match {
case tpd: TypeParameterDef => tp == tpd.tp
case _ => false
}
override def hashCode: Int = tp.hashCode
override def toString: String = s"TypeParameterDef($tp)"
}
object TypeParameterDef {
def fresh(name: String, flags: Seq[Flag] = Seq.empty) = TypeParameterDef(FreshIdentifier(name), flags)
def apply(tp: TypeParameter) = new TypeParameterDef(tp)
def apply(id: Identifier, flags: Seq[Flag] = Seq.empty) = new TypeParameterDef(TypeParameter(id, flags))
def unapply(tpd: TypeParameterDef): Option[(Identifier, Seq[Flag])] = Some((tpd.id, tpd.flags))
}
/** Represents source code annotations and some other meaningful flags.
*
* In order to enable transformations on [[Flag]] instances, there is an
* implicit contract on `args` such that for each argument, either
* {{{arg: Expr | Type}}}, or there exists no [[Expressions.Expr Expr]]
* or [[Types.Type Type]] instance within arg. */
abstract class Flag(val name: String, args: Seq[Any]) extends Printable {
def asString(implicit opts: PrinterOptions): String = name + (if (args.isEmpty) "" else {
args.map(arg => self.asString(arg)(opts)).mkString("(", ", ", ")")
})
}
/** Denotes that this adt is refined by invariant ''id'' */
sealed case class HasADTInvariant(id: Identifier) extends Flag("invariant", Seq(id))
/** Denotes that this adt has an overriden equality relation given by ''id'' */
sealed case class HasADTEquality(id: Identifier) extends Flag("equality", Seq(id))
/** Compiler annotations given in the source code as @annot.
*
* @see [[Flag]] for some notes on the actual type of [[args]]. */
sealed case class Annotation(override val name: String, val args: Seq[Any]) extends Flag(name, args)
/** Algebraic datatype sort definition.
* An ADT sort is linked to a series of constructors ([[ADTConstructor]]) for this particular sort. */
class ADTSort(val id: Identifier,
val tparams: Seq[TypeParameterDef],
val constructors: Seq[ADTConstructor],
val flags: Seq[Flag]) extends Definition {
def typeArgs = tparams.map(_.tp)
def isInductive(implicit s: Symbols): Boolean = {
val base = typed
def rec(sort: TypedADTSort, seen: Set[TypedADTSort], first: Boolean = false): Boolean = {
if (!first && sort == base) true
else if (seen(sort)) false
else sort.constructors.exists(_.fields.exists(vd => typeOps.exists {
case t: ADTType => rec(t.getSort, seen + sort)
case _ => false
} (vd.getType)))
}
rec(base, Set.empty, first = true)
}
def isWellFormed(implicit s: Symbols): Boolean = {
def flatten(s: Seq[Type]): Seq[Type] = s match {
case Nil => Nil
case (head: TupleType) +: tail => flatten(head.bases ++ tail)
case (head: MapType) +: tail => flatten(head.to +: tail) // Because Map has a default.
case head +: tail => head +: flatten(tail)
}
def rec(sort: TypedADTSort, seen: Set[TypedADTSort]): Boolean = {
if (seen(sort)) false
else sort.constructors.exists(cons => flatten(cons.fields.map(_.getType)).forall {
case t: ADTType => rec(t.getSort, seen + sort)
case _ => true
})
}
rec(typed, Set.empty)
}
/** An invariant that refines this [[ADTSort]] */
def invariant(implicit s: Symbols): Option[FunDef] =
flags.collectFirst { case HasADTInvariant(id) => s.getFunction(id) }
def hasInvariant(implicit s: Symbols): Boolean = invariant.isDefined
/** An equality relation defined on this [[ADTSort]] */
def equality(implicit s: Symbols): Option[FunDef] =
flags.collectFirst { case HasADTEquality(id) => s.getFunction(id) }
def hasEquality(implicit s: Symbols): Boolean = equality.isDefined
/** Wraps this [[ADTSort]] in a in [[TypedADTSort]] with its own type parameters */
def typed(implicit s: Symbols): TypedADTSort = typed(tparams.map(_.tp))
/** Wraps this [[ADTSort]] in a in [[TypedADTSort]] with the specified type parameters */
def typed(tps: Seq[Type])(implicit s: Symbols): TypedADTSort = s.getSort(id, tps)
def copy(id: Identifier = id,
tparams: Seq[TypeParameterDef] = tparams,
constructors: Seq[ADTConstructor] = constructors,
flags: Seq[Flag] = flags): ADTSort = new ADTSort(id, tparams, constructors, flags)
}
/** Case classes/ ADT constructors. For single-case classes these may coincide
*
* @param id -- The identifier that refers to this ADT constructor.
* @param fields -- The fields of this constructor (types may depend on sorts type params).
*/
class ADTConstructor(
val id: Identifier,
val sort: Identifier,
val fields: Seq[ValDef]) extends Tree {
def getSort(implicit s: Symbols): ADTSort = s.getSort(sort)
/** Returns the index of the field with the specified id */
def selectorID2Index(id: Identifier) : Int = {
val index = fields.indexWhere(_.id == id)
if (index < 0) {
scala.sys.error(
"Could not find '"+id+"' ("+id.uniqueName+") within "+
fields.map(_.id.uniqueName).mkString(", ")
)
} else index
}
/** Wraps this [[ADTConstructor]] in a in [[TypedADTConstructor]] with its sort's type parameters */
def typed(implicit s: Symbols): TypedADTConstructor = typed(getSort.typeArgs)
/** Wraps this [[ADTConstructor]] in a in [[TypedADTConstructor]] with the specified type parameters */
def typed(tps: Seq[Type])(implicit s: Symbols): TypedADTConstructor = s.getConstructor(id, tps)
def copy(id: Identifier = id,
sort: Identifier = sort,
fields: Seq[ValDef] = fields): ADTConstructor = new ADTConstructor(id, sort, fields)
override def equals(that: Any): Boolean = that match {
case c: ADTConstructor => id == c.id
case _ => false
}
override def hashCode: Int = id.hashCode
}
/** Represents an [[ADTSort]] whose type parameters have been instantiated to ''tps'' */
case class TypedADTSort private(definition: ADTSort, tps: Seq[Type])(implicit val symbols: Symbols) extends Tree {
require(tps.length == definition.tparams.length)
copiedFrom(definition)
@inline def id: Identifier = definition.id
@inline def invariant: Option[TypedFunDef] = _invariant.get
private[this] val _invariant = Lazy(definition.invariant.map(_.typed(tps)))
@inline def hasInvariant: Boolean = invariant.isDefined
@inline def equality: Option[TypedFunDef] = _equality.get
private[this] val _equality = Lazy(definition.equality.map(_.typed(tps)))
@inline def hasEquality: Boolean = equality.isDefined
@inline def tpSubst: Map[TypeParameter, Type] = _tpSubst.get
private[this] val _tpSubst = Lazy((definition.typeArgs zip tps).toMap.filter(tt => tt._1 != tt._2))
/** A [[Types.Type Type]] instantiated with this [[TypedADTSort]]'s type instantiation */
def instantiate(t: Type): Type = typeOps.instantiateType(t, tpSubst)
/** A [[Expressions.Expr Expr]] instantiated with this [[TypedADTSort]]'s type instantiation */
def instantiate(e: Expr): Expr = typeOps.instantiateType(e, tpSubst)
/** A [[Definitions.Flag Flag]] instantiated with this [[TypedADTSort]]'s type instantiation */
def instantiate(f: Flag): Flag = {
val (ids, exprs, types, recons) = deconstructor.deconstruct(f)
recons(ids, exprs.map(instantiate), types.map(instantiate))
}
/** The flags of the respective [[ADTSort]] instantiated with the real type parameters */
@inline def flags: Seq[Flag] = _flags.get
private[this] val _flags = Lazy(definition.flags.map(instantiate))
val constructors: Seq[TypedADTConstructor] =
definition.constructors map (TypedADTConstructor(_, this))
}
/** Represents an [[ADTConstructor]] whose type parameters have been instantiated to ''tps'' */
case class TypedADTConstructor private(definition: ADTConstructor, sort: TypedADTSort) extends Tree {
copiedFrom(definition)
@inline def id: Identifier = definition.id
@inline def tps: Seq[Type] = sort.tps
@inline def fields: Seq[ValDef] = _fields.get
private[this] val _fields = Lazy({
if (sort.tpSubst.isEmpty) definition.fields
else definition.fields.map(vd => vd.copy(
tpe = sort.instantiate(vd.tpe),
flags = vd.flags.map(sort.instantiate)
))
})
}
/** Function definition
*
* @param id -- The identifier which will refer to this function.
* @param tparams -- The type parameters this function takes.
* @param params -- The functions formal arguments (types may depend on [[tparams]]).
* @param returnType -- The function's return type (may depend on [[tparams]]).
* @param fullBody -- The body of this function.
* @param flags -- Flags that annotate this function with attributes.
*/
class FunDef(
val id: Identifier,
val tparams: Seq[TypeParameterDef],
val params: Seq[ValDef],
val returnType: Type,
val fullBody: Expr,
val flags: Seq[Flag]
) extends Definition {
/** Wraps this [[FunDef]] in a in [[TypedFunDef]] with its own type parameters */
def typed(implicit s: Symbols): TypedFunDef = typed(tparams.map(_.tp))
/** Wraps this [[FunDef]] in a in [[TypedFunDef]] with the specified type parameters */
def typed(tps: Seq[Type])(implicit s: Symbols): TypedFunDef = s.getFunction(id, tps)
/* Auxiliary methods */
def isRecursive(implicit s: Symbols) = s.isRecursive(id)
@inline def typeArgs: Seq[TypeParameter] = _typeArgs.get
private[this] val _typeArgs = Lazy(tparams.map(_.tp))
/** Applies this function on its formal parameters */
@inline def applied = FunctionInvocation(id, typeArgs, params map (_.toVariable))
/** The (non-dependent) return type of this function definition */
def getType(implicit s: Symbols) = returnType.getType
def copy(
id: Identifier = this.id,
tparams: Seq[TypeParameterDef] = this.tparams,
params: Seq[ValDef] = this.params,
returnType: Type = this.returnType,
fullBody: Expr = this.fullBody,
flags: Seq[Flag] = this.flags
): FunDef = new FunDef(id, tparams, params, returnType, fullBody, flags).copiedFrom(this)
}
/** Represents a [[FunDef]] whose type parameters have been instantiated with the specified types */
case class TypedFunDef private(fd: FunDef, tps: Seq[Type])(implicit val symbols: Symbols) extends Tree {
require(tps.length == fd.tparams.length)
copiedFrom(fd)
val id = fd.id
def signature = {
if (tps.nonEmpty) {
id.toString+tps.mkString("[", ", ", "]")
} else {
id.toString
}
}
@inline def tpSubst: Map[TypeParameter, Type] = _tpSubst.get
private[this] val _tpSubst = Lazy((fd.typeArgs zip tps).toMap.filter(tt => tt._1 != tt._2))
/** A [[Types.Type Type]] instantiated with this [[TypedFunDef]]'s type instantiation */
def instantiate(t: Type): Type = typeOps.instantiateType(t, tpSubst)
/** A [[Expressions.Expr Expr]] instantiated with this [[TypedFunDef]]'s type instantiation */
def instantiate(e: Expr): Expr = typeOps.instantiateType(e, tpSubst)
/** A [[Definitions.Flag Flag]] instantiated with this [[TypedFunDef]]'s type instantiation */
def instantiate(f: Flag): Flag = {
val (ids, exprs, types, recons) = deconstructor.deconstruct(f)
recons(ids, exprs.map(instantiate), types.map(instantiate))
}
/** A mapping from this [[TypedFunDef]]'s formal parameters to real arguments
*
* @param realArgs The arguments to which the formal arguments are mapped
*/
def paramSubst(realArgs: Seq[Expr]) = {
require(realArgs.size == params.size)
(params zip realArgs).toMap
}
/** Substitute this [[TypedFunDef]]'s formal parameters with real arguments in some expression
*
* @param realArgs The arguments to which the formal argumentas are mapped
* @param e The expression in which the substitution will take place
*/
def withParamSubst(realArgs: Seq[Expr], e: Expr) = {
exprOps.replaceFromSymbols(paramSubst(realArgs), e)
}
/** Apply this [[inox.ast.Definitions.TypedFunDef]] on specified arguments */
def applied(realArgs: Seq[Expr]): FunctionInvocation = {
FunctionInvocation(id, tps, realArgs)
}
/** Apply this [[inox.ast.Definitions.TypedFunDef]] on its formal parameters */
@inline def applied: FunctionInvocation = applied(params map { _.toVariable })
/** The paremeters of the respective [[FunDef]] instantiated with the real type parameters */
@inline def params: Seq[ValDef] = _params.get
private[this] val _params = Lazy({
if (tpSubst.isEmpty) fd.params
else fd.params.map(vd => vd.copy(
tpe = instantiate(vd.tpe),
flags = vd.flags.map(instantiate)
))
})
/** The function type corresponding to this [[TypedFunDef]]'s arguments and return type */
@inline def functionType: FunctionType = FunctionType(params.map(_.tpe), returnType)
/** The return type of the respective [[FunDef]] instantiated with the real type parameters */
@inline def returnType: Type = _returnType.get
private[this] val _returnType = Lazy(instantiate(fd.returnType))
/** The (non-dependent) return type of this typed function definition */
def getType = returnType.getType
/** The body of the respective [[FunDef]] instantiated with the real type parameters */
@inline def fullBody: Expr = _fullBody.get
private[this] val _fullBody = Lazy(instantiate(fd.fullBody))
/** The flags of the respective [[FunDef]] instantiated with the real type parameters */
@inline def flags: Seq[Flag] = _flags.get
private[this] val _flags = Lazy(fd.flags.map(instantiate))
}
}