Skip to content

Commit 78d7690

Browse files
committed
Merge pull request #823 from smarter/fix/lifting-and-inference
Always fully define the types of lifted expressions
2 parents 9ede7d0 + 78488cb commit 78d7690

File tree

7 files changed

+59
-44
lines changed

7 files changed

+59
-44
lines changed

src/dotty/tools/dotc/typer/Applications.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import Names._
2121
import StdNames._
2222
import ProtoTypes._
2323
import EtaExpansion._
24+
import Inferencing._
2425
import collection.mutable
2526
import config.Printers._
2627
import TypeApplications._

src/dotty/tools/dotc/typer/EtaExpansion.scala

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import Decorators._
1313
import Names._
1414
import StdNames._
1515
import Trees._
16+
import Inferencing._
1617
import util.Positions._
1718
import collection.mutable
1819

@@ -24,7 +25,8 @@ object EtaExpansion {
2425
if (isPureExpr(expr)) expr
2526
else {
2627
val name = ctx.freshName(prefix).toTermName
27-
val sym = ctx.newSymbol(ctx.owner, name, EmptyFlags, expr.tpe.widen, coord = positionCoord(expr.pos))
28+
val liftedType = fullyDefinedType(expr.tpe.widen, "lifted expression", expr.pos)
29+
val sym = ctx.newSymbol(ctx.owner, name, EmptyFlags, liftedType, coord = positionCoord(expr.pos))
2830
defs += ValDef(sym, expr)
2931
ref(sym.valRef)
3032
}

src/dotty/tools/dotc/typer/Inferencing.scala

Lines changed: 1 addition & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ import config.Printers._
2020
import annotation.tailrec
2121
import collection.mutable
2222

23-
trait Inferencing { this: Checking =>
23+
object Inferencing {
2424

2525
import tpd._
2626

@@ -197,47 +197,6 @@ trait Inferencing { this: Checking =>
197197
case _ => NoType
198198
}
199199

200-
/** Ensure that the first type in a list of parent types Ps points to a non-trait class.
201-
* If that's not already the case, add one. The added class type CT is determined as follows.
202-
* First, let C be the unique class such that
203-
* - there is a parent P_i such that P_i derives from C, and
204-
* - for every class D: If some parent P_j, j <= i derives from D, then C derives from D.
205-
* Then, let CT be the smallest type which
206-
* - has C as its class symbol, and
207-
* - for all parents P_i: If P_i derives from C then P_i <:< CT.
208-
*/
209-
def ensureFirstIsClass(parents: List[Type])(implicit ctx: Context): List[Type] = {
210-
def realClassParent(cls: Symbol): ClassSymbol =
211-
if (!cls.isClass) defn.ObjectClass
212-
else if (!(cls is Trait)) cls.asClass
213-
else cls.asClass.classParents match {
214-
case parentRef :: _ => realClassParent(parentRef.symbol)
215-
case nil => defn.ObjectClass
216-
}
217-
def improve(candidate: ClassSymbol, parent: Type): ClassSymbol = {
218-
val pcls = realClassParent(parent.classSymbol)
219-
if (pcls derivesFrom candidate) pcls else candidate
220-
}
221-
parents match {
222-
case p :: _ if p.classSymbol.isRealClass => parents
223-
case _ =>
224-
val pcls = (defn.ObjectClass /: parents)(improve)
225-
typr.println(i"ensure first is class $parents%, % --> ${parents map (_ baseTypeWithArgs pcls)}%, %")
226-
val ptype = ctx.typeComparer.glb(
227-
defn.ObjectType :: (parents map (_ baseTypeWithArgs pcls)))
228-
ptype :: parents
229-
}
230-
}
231-
232-
/** Ensure that first parent tree refers to a real class. */
233-
def ensureFirstIsClass(parents: List[Tree], pos: Position)(implicit ctx: Context): List[Tree] = parents match {
234-
case p :: ps if p.tpe.classSymbol.isRealClass => parents
235-
case _ =>
236-
// add synthetic class type
237-
val first :: _ = ensureFirstIsClass(parents.tpes)
238-
TypeTree(checkFeasible(first, pos, d"\n in inferred parent $first")).withPos(pos) :: parents
239-
}
240-
241200
/** Interpolate those undetermined type variables in the widened type of this tree
242201
* which are introduced by type application contained in the tree.
243202
* If such a variable appears covariantly in type `tp` or does not appear at all,

src/dotty/tools/dotc/typer/Namer.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import ErrorReporting._
1616
import tpd.ListOfTreeDecorator
1717
import config.Printers._
1818
import Annotations._
19+
import Inferencing._
1920
import transform.ValueClasses._
2021
import language.implicitConversions
2122

src/dotty/tools/dotc/typer/Typer.scala

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import Flags._
2121
import Decorators._
2222
import ErrorReporting._
2323
import Checking._
24+
import Inferencing._
2425
import EtaExpansion.etaExpand
2526
import dotty.tools.dotc.transform.Erasure.Boxing
2627
import util.Positions._
@@ -55,7 +56,7 @@ object Typer {
5556
assert(tree.pos.exists, s"position not set for $tree # ${tree.uniqueId}")
5657
}
5758

58-
class Typer extends Namer with TypeAssigner with Applications with Implicits with Inferencing with Checking {
59+
class Typer extends Namer with TypeAssigner with Applications with Implicits with Checking {
5960

6061
import Typer._
6162
import tpd.{cpy => _, _}
@@ -977,6 +978,47 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
977978
// 4. Polymorphic type defs override nothing.
978979
}
979980

981+
/** Ensure that the first type in a list of parent types Ps points to a non-trait class.
982+
* If that's not already the case, add one. The added class type CT is determined as follows.
983+
* First, let C be the unique class such that
984+
* - there is a parent P_i such that P_i derives from C, and
985+
* - for every class D: If some parent P_j, j <= i derives from D, then C derives from D.
986+
* Then, let CT be the smallest type which
987+
* - has C as its class symbol, and
988+
* - for all parents P_i: If P_i derives from C then P_i <:< CT.
989+
*/
990+
def ensureFirstIsClass(parents: List[Type])(implicit ctx: Context): List[Type] = {
991+
def realClassParent(cls: Symbol): ClassSymbol =
992+
if (!cls.isClass) defn.ObjectClass
993+
else if (!(cls is Trait)) cls.asClass
994+
else cls.asClass.classParents match {
995+
case parentRef :: _ => realClassParent(parentRef.symbol)
996+
case nil => defn.ObjectClass
997+
}
998+
def improve(candidate: ClassSymbol, parent: Type): ClassSymbol = {
999+
val pcls = realClassParent(parent.classSymbol)
1000+
if (pcls derivesFrom candidate) pcls else candidate
1001+
}
1002+
parents match {
1003+
case p :: _ if p.classSymbol.isRealClass => parents
1004+
case _ =>
1005+
val pcls = (defn.ObjectClass /: parents)(improve)
1006+
typr.println(i"ensure first is class $parents%, % --> ${parents map (_ baseTypeWithArgs pcls)}%, %")
1007+
val ptype = ctx.typeComparer.glb(
1008+
defn.ObjectType :: (parents map (_ baseTypeWithArgs pcls)))
1009+
ptype :: parents
1010+
}
1011+
}
1012+
1013+
/** Ensure that first parent tree refers to a real class. */
1014+
def ensureFirstIsClass(parents: List[Tree], pos: Position)(implicit ctx: Context): List[Tree] = parents match {
1015+
case p :: ps if p.tpe.classSymbol.isRealClass => parents
1016+
case _ =>
1017+
// add synthetic class type
1018+
val first :: _ = ensureFirstIsClass(parents.tpes)
1019+
TypeTree(checkFeasible(first, pos, d"\n in inferred parent $first")).withPos(pos) :: parents
1020+
}
1021+
9801022
/** If this is a real class, make sure its first parent is a
9811023
* constructor call. Cannot simply use a type. Overridden in ReTyper.
9821024
*/

test/dotc/tests.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ class tests extends CompilerTest {
5353
// This directory doesn't exist anymore
5454
// @Test def pickle_pickling = compileDir(coreDir, "pickling", testPickling)
5555
@Test def pickle_ast = compileDir(dotcDir, "ast", testPickling)
56+
@Test def pickle_inf = compileFile(posDir, "pickleinf", testPickling)
5657

5758
//@Test def pickle_core = compileDir(dotcDir, "core", testPickling, xerrors = 2) // two spurious comparison errors in Types and TypeOps
5859

tests/pos/pickleinf.scala

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
class Bar[N] {
2+
def bar(name: N, dummy: Int = 42): N = name
3+
}
4+
5+
object Test {
6+
def test(): Unit = {
7+
(new Bar).bar(10)
8+
}
9+
}

0 commit comments

Comments
 (0)