Skip to content

Commit c6ec390

Browse files
committed
Add PFunction type
1 parent fb10bdc commit c6ec390

4 files changed

Lines changed: 39 additions & 19 deletions

File tree

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

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -436,6 +436,16 @@ case class PWandType()(val pos: (Position, Position)) extends PInternalType {
436436
override def isValidOrUndeclared = true
437437
}
438438

439+
/**
440+
*/
441+
case class PFunctionType(resultType: PType) extends PType {
442+
override val pos: (Position, Position) = resultType.pos
443+
override def isValidOrUndeclared: Boolean = resultType.isValidOrUndeclared
444+
override def substitute(ts: PTypeSubstitution): PType = this.copy(resultType = resultType.substitute(ts))
445+
override def subNodes: Seq[PType] = Seq(resultType)
446+
override def toString = "$fn:" + resultType.toString
447+
}
448+
439449
///////////////////////////////////////////////////////////////////////////////////////
440450
// Expressions
441451
// typeSubstitutions are the possible substitutions used for type checking and inference
@@ -622,14 +632,14 @@ case class PCall(func: PIdnUse, args: Seq[PExp], typeAnnotated: Option[PType] =
622632
override def macroArgs = args
623633

624634
override def signatures = if (function != null && function.formalArgs.size == args.size) (function match {
625-
case _: PFunction => List(
626-
new PTypeSubstitution(args.indices.map(i => POpApp.pArg(i).domain.name -> function.formalArgs(i).typ) :+ (POpApp.pRes.domain.name -> function.typ))
635+
case pf: PFunction => List(
636+
new PTypeSubstitution(args.indices.map(i => POpApp.pArg(i).domain.name -> pf.formalArgs(i).typ) :+ (POpApp.pRes.domain.name -> pf.typ.resultType))
627637
)
628638
case pdf: PDomainFunction =>
629639
List(
630640
new PTypeSubstitution(
631-
args.indices.map(i => POpApp.pArg(i).domain.name -> function.formalArgs(i).typ.substitute(domainTypeRenaming.get)) :+
632-
(POpApp.pRes.domain.name -> pdf.typ.substitute(domainTypeRenaming.get)))
641+
args.indices.map(i => POpApp.pArg(i).domain.name -> pdf.formalArgs(i).typ.substitute(domainTypeRenaming.get)) :+
642+
(POpApp.pRes.domain.name -> pdf.typ.resultType.substitute(domainTypeRenaming.get)))
633643
)
634644

635645
})
@@ -1380,7 +1390,8 @@ trait PAnyFunction extends PSingleMember with PTypedDeclaration {
13801390

13811391
def formalArgs: Seq[PAnyFormalArgDecl]
13821392

1383-
def typ: PType
1393+
def resultType: PType
1394+
override def typ: PFunctionType = PFunctionType(resultType)
13841395
}
13851396

13861397
case class PProgram(imports: Seq[PImport], macros: Seq[PDefine], domains: Seq[PDomain], fields: Seq[PField], functions: Seq[PFunction], predicates: Seq[PPredicate], methods: Seq[PMethod], extensions: Seq[PExtender], errors: Seq[ParseReport])(val pos: (Position, Position)) extends PNode
@@ -1411,16 +1422,16 @@ case class PMethod(idndef: PIdnDef, formalArgs: Seq[PFormalArgDecl], formalRetur
14111422

14121423
case class PDomain(idndef: PIdnDef, typVars: Seq[PTypeVarDecl], funcs: Seq[PDomainFunction], axioms: Seq[PAxiom], interpretations: Option[Map[String, String]])
14131424
(val pos: (Position, Position), val annotations: Seq[(String, Seq[String])]) extends PSingleMember
1414-
case class PFunction(idndef: PIdnDef, formalArgs: Seq[PFormalArgDecl], typ: PType, pres: Seq[PExp], posts: Seq[PExp], body: Option[PExp])
1425+
case class PFunction(idndef: PIdnDef, formalArgs: Seq[PFormalArgDecl], resultType: PType, pres: Seq[PExp], posts: Seq[PExp], body: Option[PExp])
14151426
(val pos: (Position, Position), val annotations: Seq[(String, Seq[String])]) extends PAnyFunction {
1416-
def deepCopy(idndef: PIdnDef = this.idndef, formalArgs: Seq[PFormalArgDecl] = this.formalArgs, typ: PType = this.typ, pres: Seq[PExp] = this.pres, posts: Seq[PExp] = this.posts, body: Option[PExp] = this.body): PFunction = {
1427+
def deepCopy(idndef: PIdnDef = this.idndef, formalArgs: Seq[PFormalArgDecl] = this.formalArgs, resultType: PType = this.resultType, pres: Seq[PExp] = this.pres, posts: Seq[PExp] = this.posts, body: Option[PExp] = this.body): PFunction = {
14171428
StrategyBuilder.Slim[PNode]({
1418-
case p: PFunction => PFunction(idndef, formalArgs, typ, pres, posts, body)(p.pos, p.annotations)
1429+
case p: PFunction => PFunction(idndef, formalArgs, resultType, pres, posts, body)(p.pos, p.annotations)
14191430
}).execute[PFunction](this)
14201431
}
14211432
}
14221433

1423-
case class PDomainFunction(idndef: PIdnDef, formalArgs: Seq[PAnyFormalArgDecl], typ: PType, unique: Boolean, interpretation: Option[String])
1434+
case class PDomainFunction(idndef: PIdnDef, formalArgs: Seq[PAnyFormalArgDecl], resultType: PType, unique: Boolean, interpretation: Option[String])
14241435
(val domainName:PIdnUse)(val pos: (Position, Position), val annotations: Seq[(String, Seq[String])]) extends PAnyFunction
14251436
case class PAxiom(idndef: Option[PIdnDef], exp: PExp)(val domainName:PIdnUse)(val pos: (Position, Position), val annotations: Seq[(String, Seq[String])]) extends PScope
14261437
case class PField(fields: Seq[PFieldDecl])(val pos: (Position, Position), val annotations: Seq[(String, Seq[String])]) extends PMember {

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

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,7 @@ case class TypeChecker(names: NameAnalyser) {
123123
f.pres foreach (check(_, Bool))
124124
resultAllowed = true
125125
f.posts foreach (check(_, Bool))
126-
f.body.foreach(check(_, f.typ)) //result in the function body gets the error message somewhere else
126+
f.body.foreach(check(_, f.typ.resultType)) //result in the function body gets the error message somewhere else
127127
resultAllowed = false
128128
curFunction = null
129129
}
@@ -413,6 +413,8 @@ case class TypeChecker(names: NameAnalyser) {
413413
case PMapType(keyType, valueType) =>
414414
check(keyType)
415415
check(valueType)
416+
case PFunctionType(resultType) =>
417+
check(resultType)
416418
case t: PExtender =>
417419
t.typecheck(this, names).getOrElse(Nil) foreach (message =>
418420
messages ++= FastMessaging.message(t, message))
@@ -620,7 +622,7 @@ case class TypeChecker(names: NameAnalyser) {
620622
psl match {
621623
case r@PResultLit() =>
622624
if (resultAllowed)
623-
setType(curFunction.typ)
625+
setType(curFunction.typ.resultType)
624626
else
625627
issueError(r, "'result' can only be used in function postconditions")
626628
case _ =>

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

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -344,12 +344,12 @@ case class Translator(program: PProgram) {
344344
case piu @ PIdnUse(name) =>
345345
piu.decl match {
346346
case _: PAnyVarDecl => LocalVar(name, ttyp(pexp.typ))(pos, info)
347-
case pf: PField =>
348-
/* A malformed AST where a field is dereferenced without a receiver */
349-
Consistency.messages ++= FastMessaging.message(piu, s"expected expression but found field $name")
350-
LocalVar(pf.idndef.name, ttyp(pf.typ))(pos, info)
351-
case _ =>
352-
sys.error("should not occur in type-checked program")
347+
case null => sys.error("should not occur in type-checked program")
348+
/* A malformed AST where a field, function or other declaration is used as a variable */
349+
case decl =>
350+
Consistency.messages ++= FastMessaging.message(piu, s"expected variable identifier but found `${decl.idndef.name}`")
351+
// Avoid translating `pexp.typ` here since it may be invalid (e.g. `PFunctionType`)
352+
LocalVar(name, InternalType)(pos, info)
353353
}
354354
case pbe @ PBinExp(left, op, right) =>
355355
val (l, r) = (exp(left), exp(right))
@@ -466,7 +466,7 @@ case class Translator(program: PProgram) {
466466
if (par == null) sys.error("cannot use 'result' outside of function")
467467
par = par.parent.get
468468
}
469-
Result(ttyp(par.asInstanceOf[PFunction].typ))(pos, info)
469+
Result(ttyp(par.asInstanceOf[PFunction].typ.resultType))(pos, info)
470470
case PBoolLit(b) =>
471471
if (b) TrueLit()(pos, info) else FalseLit()(pos, info)
472472
case PNullLit() =>
@@ -709,6 +709,8 @@ case class Translator(program: PProgram) {
709709
case t: PExtender => t.translateType(this)
710710
case PUnknown() =>
711711
sys.error("unknown type unexpected here")
712+
case PFunctionType(_) =>
713+
sys.error("unexpected use of internal typ")
712714
case PPredicateType() =>
713715
sys.error("unexpected use of internal typ")
714716
}

src/test/resources/all/issues/silver/0128.vpr

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,9 @@ function balance(this: Ref): Int
66
method deposit()
77
//:: ExpectedOutput(typechecker.error)
88
ensures balance == 5
9-
{}
9+
{}
10+
11+
method deposit2()
12+
//:: ExpectedOutput(consistency.error)
13+
ensures balance == balance
14+
{}

0 commit comments

Comments
 (0)