Skip to content

Commit 274af3c

Browse files
authored
Merge pull request #758 from viperproject/meilers_type_var_defaults
No longer substituting Int as default for unconstrained type variables inside domains
2 parents 9d401d8 + f9e5467 commit 274af3c

3 files changed

Lines changed: 57 additions & 6 deletions

File tree

src/main/scala/viper/silver/parser/ParseAst.scala

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -321,6 +321,7 @@ object PTypeVar {
321321
}
322322

323323
val sep = "#"
324+
val domainNameSep = "%"
324325

325326
//TODO: do this properly
326327
def isFreePTVName(s: String) = s.contains(sep)
@@ -342,9 +343,18 @@ object PTypeVar {
342343
freshTypeSubstitution(tvs map (tv => tv.domain.name))
343344
}
344345

345-
def freshTypeSubstitution(tvns: Seq[String]): PTypeRenaming = {
346+
def freshTypeSubstitution(tvns: Seq[String], domainName: Option[String] = None): PTypeRenaming = {
346347
val ind = lastIndex.getAndIncrement()
347-
new PTypeRenaming((tvns map (tv => tv -> getFreshName(tv, ind))).toMap)
348+
new PTypeRenaming((tvns map (tv => {
349+
val tvName = domainName match {
350+
case Some(dn) =>
351+
// Choose a name for the type variable that contains the domain name.
352+
// This enables us to choose a useful default in case the type variable is unconstrained.
353+
dn + domainNameSep + tv
354+
case None => tv
355+
}
356+
tv -> getFreshName(tvName, ind)
357+
})).toMap)
348358
}
349359
}
350360

src/main/scala/viper/silver/parser/Resolver.scala

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -492,9 +492,31 @@ case class TypeChecker(names: NameAnalyser) {
492492

493493
def ground(exp: PExp, pts: PTypeSubstitution): PTypeSubstitution = {
494494
pts.m.flatMap(kv => kv._2.freeTypeVariables &~ pts.m.keySet).foldLeft(pts)((ts, fv) => {
495-
messages ++= FastMessaging.message(exp,
496-
s"Unconstrained type parameter, substituting default type ${PTypeSubstitution.defaultType}.", error = false)
497-
ts.add(PTypeVar(fv), PTypeSubstitution.defaultType).toOption.get
495+
var chosenType: PType = PTypeSubstitution.defaultType
496+
curMember match {
497+
case ax: PAxiom if ax.parent.exists(p => p.isInstanceOf[PDomain]) =>
498+
// If we are inside the domain that defines the type variable, then we choose the type variable itself
499+
// as the default.
500+
val domain = ax.parent.get.asInstanceOf[PDomain]
501+
// The name pf domain function application type variables has the form
502+
// domainName + PTypeVar.domainNameSep + typeVarName + PTypeVar.sep + index
503+
if (fv.startsWith(domain.idndef.name + PTypeVar.domainNameSep)) {
504+
var tvName = fv.substring(domain.idndef.name.length + 1)
505+
if (tvName.contains(PTypeVar.sep)) {
506+
tvName = tvName.substring(0, tvName.indexOf(PTypeVar.sep))
507+
if (domain.typVars.exists(tv => tv.idndef.name == tvName)) {
508+
// The type variable refers to an actual type variable of the current domain.
509+
chosenType = PTypeVar(tvName)
510+
}
511+
}
512+
}
513+
case _ =>
514+
}
515+
if (chosenType == PTypeSubstitution.defaultType) {
516+
messages ++= FastMessaging.message(exp,
517+
s"Unconstrained type parameter, substituting default type ${PTypeSubstitution.defaultType}.", error = false)
518+
}
519+
ts.add(PTypeVar(fv), chosenType).toOption.get
498520
})
499521
}
500522

@@ -642,7 +664,7 @@ case class TypeChecker(names: NameAnalyser) {
642664

643665
case pdf@PDomainFunction(_, _, _, _, _) =>
644666
val domain = names.definition(curMember)(pdf.domainName).get.asInstanceOf[PDomain]
645-
val fdtv = PTypeVar.freshTypeSubstitution((domain.typVars map (tv => tv.idndef.name)).distinct) //fresh domain type variables
667+
val fdtv = PTypeVar.freshTypeSubstitution((domain.typVars map (tv => tv.idndef.name)).distinct, Some(domain.idndef.name)) //fresh domain type variables
646668
pfa.domainTypeRenaming = Some(fdtv)
647669
pfa._extraLocalTypeVariables = (domain.typVars map (tv => PTypeVar(tv.idndef.name))).toSet
648670
extraReturnTypeConstraint = explicitType
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
// Any copyright is dedicated to the Public Domain.
2+
// http://creativecommons.org/publicdomain/zero/1.0/
3+
4+
domain Option[T] {
5+
axiom ax_Option_None_discr {
6+
Option_discr(Option_None()) == 0
7+
}
8+
function Option_discr(Option[T]): Int
9+
function Option_None(): Option[T]
10+
function Option_Some(T): Option[T]
11+
}
12+
13+
method m() {
14+
assert Option_discr((Option_None(): Option[Bool])) == 0;
15+
assert Option_discr((Option_None(): Option[Ref])) == 0;
16+
17+
//:: ExpectedOutput(assert.failed:assertion.false)
18+
assert Option_discr((Option_None(): Option[Perm])) == 1;
19+
}

0 commit comments

Comments
 (0)