Skip to content

Commit 8d68e0d

Browse files
authored
Fix type-checker crash when encountering an invalid ADT (#897)
* adds bug witness * fixes crash in the type-checker when typing a match expression for an ADT that has type UnknownType
1 parent e0857c4 commit 8d68e0d

File tree

2 files changed

+37
-3
lines changed

2 files changed

+37
-3
lines changed

src/main/scala/viper/gobra/frontend/info/implementation/typing/ghost/GhostIdTyping.scala

+8-3
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ package viper.gobra.frontend.info.implementation.typing.ghost
99
import org.bitbucket.inkytonik.kiama.util.Messaging.noMessages
1010
import viper.gobra.ast.frontend.{PExpression, PFieldDecl, PIdnNode, PMatchAdt}
1111
import viper.gobra.frontend.info.base.SymbolTable.{AdtClause, AdtDestructor, AdtDiscriminator, BoundVariable, BuiltInFPredicate, BuiltInMPredicate, DomainFunction, GhostRegular, MatchVariable, Predicate}
12-
import viper.gobra.frontend.info.base.Type.{AdtClauseT, AssertionT, FunctionT, Type}
12+
import viper.gobra.frontend.info.base.Type.{AdtClauseT, AssertionT, FunctionT, Type, UnknownType}
1313
import viper.gobra.frontend.info.implementation.TypeInfoImpl
1414
import viper.gobra.util.Violation.violation
1515

@@ -46,8 +46,13 @@ trait GhostIdTyping { this: TypeInfoImpl =>
4646

4747
case MatchVariable(decl, p, context) => p match {
4848
case PMatchAdt(clause, fields) =>
49-
val clauseT = context.symbType(clause).asInstanceOf[AdtClauseT]
50-
clauseT.typeAt(fields.indexOf(decl))
49+
val clauseT = context.symbType(clause)
50+
clauseT match {
51+
case clauseT: AdtClauseT => clauseT.typeAt(fields.indexOf(decl))
52+
// the following case is possible, e.g., if the clause is not well-defined
53+
// and, thus, `clauseT` is `UnknownType`:
54+
case _ => UnknownType
55+
}
5156

5257
case e: PExpression => context.typ(e)
5358
case _ => violation("untypeable")
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
// Any copyright is dedicated to the Public Domain.
2+
// http://creativecommons.org/publicdomain/zero/1.0/
3+
4+
package matcherror1
5+
6+
// this test case checks that Gobra does not crash when
7+
// typing a match expression if the corresponding ADT type
8+
// is not well-defined.
9+
10+
ghost type Trace adt {
11+
RootEntry{}
12+
SendEntry{
13+
//:: ExpectedOutput(type_error)
14+
msg InexistentType // unknown identifier
15+
prev Trace
16+
}
17+
}
18+
19+
ghost
20+
decreases _ // assume termination instead of using `len(t)`, which would cause another type error
21+
ensures 0 <= res
22+
pure func (t Trace) length() (res int) {
23+
return match t {
24+
case RootEntry{}: 0
25+
// we need a recursive call to trigger the error in a previous version of Gobra
26+
//:: ExpectedOutput(type_error)
27+
case SendEntry{_, ?p}: 1 + p.length() // `length` is an unknown identifier as `Trace` is malformed
28+
}
29+
}

0 commit comments

Comments
 (0)