-
Notifications
You must be signed in to change notification settings - Fork 28
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Parsing and type-checking generics #671
base: master
Are you sure you want to change the base?
Conversation
- generated gobra parser code - added Ast nodes for type parameters and type arguments - modified parse tree translator
- modified parser and parse tree translator accordingly - implemented ambiguity resolution for indexed expression (normal index expression or type arguments)
- add tests - fix some issues in the parse tree translator and the pretty printer
… underlying type of type parameters
This reverts commit 3725a9b.
These are the merged changes. First of all, the unit tests fail because of an issue I already mentioned. It has to do with this PR (#634) It somehow breaks some of my unit tests. It always complains that Second, the GobraTests of the integration suit is stuck. I also don't know what the issue is here. Before merging everything worked fine. Note that before the merge with the current master everything was working fine which can be seen here: https://github.com/koflin/gobra/tree/generics-before-merge. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Some comments
src/main/antlr4/.antlr/GoLexer.java
Outdated
@@ -0,0 +1,606 @@ | |||
// Generated from s:\GitHub\gobra\src\main\antlr4\GoLexer.g4 by ANTLR 4.9.2 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove this file
@@ -2775,6 +2780,7 @@ object Desugar extends LazyLogging { | |||
for { | |||
dArgs <- sequence(args.map { x => option(x.map(exprD(ctx, info)(_))) }) | |||
idT = info.typ(base) match { | |||
// TODO handle this |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
handle what? please make the comment more concrete.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It was a comment for myself, I'll remove it
@@ -22,6 +22,7 @@ trait UnderlyingType { this: TypeInfoImpl => | |||
lazy val underlyingType: Type => Type = | |||
attr[Type, Type] { | |||
case Single(DeclaredT(t: PTypeDecl, context: ExternalTypeInfo)) => underlyingType(context.symbType(t.right)) | |||
case Single(TypeParameterT(_, t: PInterfaceType, ctx)) => underlyingType(ctx.symbType(t)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this looks as if the underlying type of a type parameter is the underlying type of its constraint. Is this intended? Why is this correct?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, the underlying type of a type parameter is the underlying type of its type constraint (interface) https://go.dev/ref/spec#Underlying_types
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
then please add a comment
case _ => false | ||
} | ||
} | ||
|
||
def isTypeParameter(t: Type): Boolean = t match { | ||
case TypeParameterT(_, _, _) => true |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
case TypeParameterT(_, _, _) => true | |
case _: TypeParameterT => true |
@@ -35,6 +35,9 @@ trait AmbiguityResolution { this: TypeInfoImpl => | |||
case _ => Left(n) | |||
}) | |||
|
|||
case n: PIndexedExp => | |||
if (exprOrType(n.base).isLeft) Left(n) else Right(n) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
add a comment
override def withChildren(children: Seq[Any], pos: Option[(Position, Position)], forceRewrite: Boolean): this.type = { | ||
assert(pos.isEmpty, "The pos argument must be set to nil if called on Gobra nodes.") | ||
|
||
if (!forceRewrite && this.children == children) { | ||
this | ||
} else { | ||
create(children) | ||
} | ||
} | ||
|
||
private def create(children: Seq[Any]): this.type = { | ||
import scala.reflect.runtime.{universe => reflection} | ||
val mirror = reflection.runtimeMirror(reflection.getClass.getClassLoader) | ||
val instanceMirror = mirror.reflect(this) | ||
val classSymbol = instanceMirror.symbol | ||
val classMirror = mirror.reflectClass(classSymbol) | ||
val constructorSymbol = instanceMirror.symbol.primaryConstructor.asMethod | ||
val constructorMirror = classMirror.reflectConstructor(constructorSymbol) | ||
|
||
// Call constructor | ||
val newNode = constructorMirror(children: _*) | ||
newNode.asInstanceOf[this.type] | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is this necessary?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
viper.gobra.ast.internal.Node needs this to work correctly. It is taken from viper.gobra.ast.internal.Rewritable and modified slightly
import scala.annotation.tailrec | ||
sealed trait TypeSet | ||
|
||
object TypeSet { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
add more documentation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I mean for the entire file
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yes, sorry. I forgot this one
@@ -160,6 +166,29 @@ trait TypeTyping extends BaseTyping { this: TypeInfoImpl => | |||
|
|||
case _ => violation(s"expected type, but got $n") | |||
} | |||
|
|||
case n: PIndexedExp => | |||
resolve(n) match { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
also deal with unexpected matches (via violation).
val typeMap = f.args.filter(isTypeParameter).zip(fc.args.map(exprType)).map { | ||
case (TypeParameterT(id, _, _), typ) => (PIdnDef(id.name), typ) | ||
}.toMap[PIdnDef, Type] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am not sure this is correct. If only the second argument is a type parameter, would you then not zip the second parameter with the first argument?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yes you are right, I'll correct this
val typeMap = args.filter(isTypeParameter).zip(argTypes).map { | ||
case (TypeParameterT(id, _, _), typ) => (PIdnDef(id.name), typ) | ||
}.toMap[PIdnDef, Type] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
please refactor the type inference into a separate method
These are my changes to support parsing and type-checking generics.