Skip to content
Permalink
Browse files

Infer correct NominalType views even without the NominalType.

In inferTypes, we used to replace structural views of NominalTypes after
constructing all table types. At that point, however, type inference
(which runs before table types can be determined) may have copied a
structural view on its own (without the enclosing NominalType) into
another type. For instance, this happens in the typing of GroupBy, where
the "by" type needs to be copied purely as a structural view. In these
cases the resulting NoType could not be patched to the correct type. To
fix this problem we use the new type UnassignedStructuralType(ts) with
the same TypeSymbol as the surrounding NominalType in table types, which
can be patched even after the NominalType has been lost.

The only remaining use of NoType in StarAnd can be replaced by
UnassignedType, thus eliminating NoType entirely.

Tests in AggregateTest.testGroupBy. Fixes issue #252.
  • Loading branch information
szeiger committed Jan 24, 2014
1 parent c59ba50 commit 20221076e0dc2e77bcdfcd0603feb4d85d8048e5
@@ -131,6 +131,19 @@ class AggregateTest extends TestkitTest[RelationalTestDB] {
val q8c = for( (key, group) <- us.map(_ => 5).groupBy(co => co) )
yield (key, group.map(co => co + co).sum )
assertEquals((Seq((5, Some(40)))), q8c.run)

println("=========================================================== q9")
val res9 = Set(
(1, Some(1)), (1, Some(2)), (1, Some(3)),
(2, Some(1)), (2, Some(2)), (2, Some(5)),
(3, Some(1)), (3, Some(9))
)
val q9 = ts.groupBy(x => x).map(_._1)
assertEquals(res9, q9.run.toSet)
val q9b = ts.map(x => x).groupBy(_.*).map(_._1)
assertEquals(res9, q9b.run.toSet)
val q9c = ts.map(x => x).groupBy(x => x).map(_._1)
assertEquals(res9, q9c.run.toSet)
}

def testIntLength {
@@ -514,7 +514,7 @@ object FwdPath {
/** A Node representing a database table. */
final case class TableNode(schemaName: Option[String], tableName: String, identity: TableIdentitySymbol, driverTable: Any) extends NullaryNode with TypedNode {
type Self = TableNode
def tpe = CollectionType(CollectionTypeConstructor.default, NominalType(identity)(NoType))
def tpe = CollectionType(CollectionTypeConstructor.default, NominalType(identity)(UnassignedStructuralType(identity)))
def nodeRebuild = copy()
override def toString = "Table " + tableName
}
@@ -108,10 +108,13 @@ final class MappedScalaType(val baseType: Type, _toBase: Any => Any, _toMapped:
override def select(sym: Symbol) = baseType.select(sym)
}

final case object NoType extends AtomicType

/** The standard type for freshly constructed nodes without an explicit type. */
final case object UnassignedType extends AtomicType

/** The type of a structural view of a NominalType before computing the
* proper type in the `inferTypes` phase. */
final case class UnassignedStructuralType(sym: TypeSymbol) extends AtomicType

/* A type with a name, as used by tables.
*
* Compiler phases which change types may keep their own representation
@@ -15,8 +15,7 @@ class InferTypes extends Phase {
}.groupBy(_._1).mapValues(v => StructType(v.map(_._2).toMap.toIndexedSeq))
logger.debug("Found Selects for NominalTypes: "+structs.keySet.mkString(", "))
def tr(n: Node): Node = n.nodeMapChildren(tr, keepType = true).nodeTypedOrCopy(n.nodeType.replace {
case t @ NominalType(tsym) if t.structuralView == NoType && structs.contains(tsym) =>
t.withStructuralView(structs(tsym))
case UnassignedStructuralType(tsym) if structs.contains(tsym) => structs(tsym)
})
tr(tree2)
}
@@ -343,7 +343,7 @@ trait JdbcStatementBuilderComponent { driver: JdbcDriver =>
final case class StarAnd(child: Node) extends UnaryNode with SimplyTypedNode {
type Self = StarAnd
protected[this] def nodeRebuild(child: Node) = StarAnd(child)
protected def buildType = NoType
protected def buildType = UnassignedType
}

override def expr(c: Node, skipParens: Boolean = false): Unit = c match {

0 comments on commit 2022107

Please sign in to comment.
You can’t perform that action at this time.