Skip to content

Rework type inference #4080

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

Merged
merged 19 commits into from
Mar 7, 2018
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion compiler/src/dotty/tools/dotc/core/TyperState.scala
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ package core
import Types._
import Flags._
import Contexts._
import util.{SimpleIdentityMap, DotClass}
import util.{SimpleIdentityMap, SimpleIdentitySet, DotClass}
import reporting._
import printing.{Showable, Printer}
import printing.Texts._
Expand Down Expand Up @@ -76,6 +76,11 @@ class TyperState(previous: TyperState /* | Null */) {
/** The uninstantiated variables */
def uninstVars = constraint.uninstVars

/** The set of uninstantiated type varibles which have this state as their owning state */
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

typo: varibles -> variables

private[this] var myOwnedVars: TypeVars = SimpleIdentitySet.empty
def ownedVars = myOwnedVars
def ownedVars_=(vs: TypeVars): Unit = myOwnedVars = vs

/** Gives for each instantiated type var that does not yet have its `inst` field
* set, the instance value stored in the constraint. Storing instances in constraints
* is done only in a temporary way for contexts that may be retracted
Expand Down Expand Up @@ -154,6 +159,7 @@ class TyperState(previous: TyperState /* | Null */) {
constraint foreachTypeVar { tvar =>
if (tvar.owningState.get eq this) tvar.owningState = new WeakReference(targetState)
}
targetState.ownedVars ++= ownedVars
targetState.gc()
reporter.flush()
isCommitted = true
Expand Down
9 changes: 7 additions & 2 deletions compiler/src/dotty/tools/dotc/core/Types.scala
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import Denotations._
import Periods._
import util.Positions.{Position, NoPosition}
import util.Stats._
import util.DotClass
import util.{DotClass, SimpleIdentitySet}
import reporting.diagnostic.Message
import reporting.diagnostic.messages.CyclicReferenceInvolving
import ast.tpd._
Expand Down Expand Up @@ -3369,7 +3369,10 @@ object Types {
private[core] def inst = myInst
private[core] def inst_=(tp: Type) = {
myInst = tp
if (tp.exists) owningState = null // no longer needed; null out to avoid a memory leak
if (tp.exists) {
owningState.get.ownedVars -= this
owningState = null // no longer needed; null out to avoid a memory leak
}
}

/** The state owning the variable. This is at first `creatorState`, but it can
Expand Down Expand Up @@ -3433,6 +3436,8 @@ object Types {
}
}

type TypeVars = SimpleIdentitySet[TypeVar]

// ------ ClassInfo, Type Bounds ------------------------------------------------------------

type TypeOrSymbol = AnyRef /* should be: Type | Symbol */
Expand Down
8 changes: 5 additions & 3 deletions compiler/src/dotty/tools/dotc/transform/Erasure.scala
Original file line number Diff line number Diff line change
Expand Up @@ -675,14 +675,16 @@ object Erasure {
super.typedStats(stats1, exprOwner).filter(!_.isEmpty)
}

override def adapt(tree: Tree, pt: Type)(implicit ctx: Context): Tree =
override def adapt(tree: Tree, pt: Type, locked: TypeVars)(implicit ctx: Context): Tree =
trace(i"adapting ${tree.showSummary}: ${tree.tpe} to $pt", show = true) {
assert(ctx.phase == ctx.erasurePhase.next, ctx.phase)
assert(ctx.phase == ctx.erasurePhase || ctx.phase == ctx.erasurePhase.next, ctx.phase)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why did this change?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure why. Some transform ran at phase erasure and used the erasure typer to do it. Seems legit. Not sure why it did not run before.

if (tree.isEmpty) tree
else if (ctx.mode is Mode.Pattern) tree // TODO: replace with assertion once pattern matcher is active
else adaptToType(tree, pt)
}
}

override def simplify(tree: Tree, pt: Type, locked: TypeVars)(implicit ctx: Context): tree.type = tree
}

def takesBridges(sym: Symbol)(implicit ctx: Context) =
sym.isClass && !sym.is(Flags.Trait | Flags.Package)
Expand Down
10 changes: 6 additions & 4 deletions compiler/src/dotty/tools/dotc/transform/TreeChecker.scala
Original file line number Diff line number Diff line change
Expand Up @@ -259,14 +259,14 @@ class TreeChecker extends Phase with SymTransformer {
tpdTree
}

override def typedUnadapted(tree: untpd.Tree, pt: Type)(implicit ctx: Context): tpd.Tree = {
override def typedUnadapted(tree: untpd.Tree, pt: Type, locked: TypeVars)(implicit ctx: Context): tpd.Tree = {
val res = tree match {
case _: untpd.TypedSplice | _: untpd.Thicket | _: EmptyValDef[_] =>
super.typedUnadapted(tree)
super.typedUnadapted(tree, pt, locked)
case _ if tree.isType =>
promote(tree)
case _ =>
val tree1 = super.typedUnadapted(tree, pt)
val tree1 = super.typedUnadapted(tree, pt, locked)
def isSubType(tp1: Type, tp2: Type) =
(tp1 eq tp2) || // accept NoType / NoType
(tp1 <:< tp2)
Expand Down Expand Up @@ -435,7 +435,7 @@ class TreeChecker extends Phase with SymTransformer {
override def ensureNoLocalRefs(tree: Tree, pt: Type, localSyms: => List[Symbol])(implicit ctx: Context): Tree =
tree

override def adapt(tree: Tree, pt: Type)(implicit ctx: Context) = {
override def adapt(tree: Tree, pt: Type, locked: TypeVars)(implicit ctx: Context) = {
def isPrimaryConstructorReturn =
ctx.owner.isPrimaryConstructor && pt.isRef(ctx.owner.owner) && tree.tpe.isRef(defn.UnitClass)
if (ctx.mode.isExpr &&
Expand All @@ -449,6 +449,8 @@ class TreeChecker extends Phase with SymTransformer {
})
tree
}

override def simplify(tree: Tree, pt: Type, locked: TypeVars)(implicit ctx: Context): tree.type = tree
}

/**
Expand Down
12 changes: 6 additions & 6 deletions compiler/src/dotty/tools/dotc/typer/Applications.scala
Original file line number Diff line number Diff line change
Expand Up @@ -546,7 +546,7 @@ trait Applications extends Compatibility { self: Typer with Dynamic =>
init()

def addArg(arg: Tree, formal: Type): Unit =
typedArgBuf += adaptInterpolated(arg, formal.widenExpr)
typedArgBuf += adapt(arg, formal.widenExpr)

def makeVarArg(n: Int, elemFormal: Type): Unit = {
val args = typedArgBuf.takeRight(n).toList
Expand Down Expand Up @@ -711,7 +711,7 @@ trait Applications extends Compatibility { self: Typer with Dynamic =>
* part. Return an optional value to indicate success.
*/
def tryWithImplicitOnQualifier(fun1: Tree, proto: FunProto)(implicit ctx: Context): Option[Tree] =
tryInsertImplicitOnQualifier(fun1, proto) flatMap { fun2 =>
tryInsertImplicitOnQualifier(fun1, proto, ctx.typerState.ownedVars) flatMap { fun2 =>
tryEither {
implicit ctx => Some(simpleApply(fun2, proto)): Option[Tree]
} {
Expand Down Expand Up @@ -1519,11 +1519,11 @@ trait Applications extends Compatibility { self: Typer with Dynamic =>
* If the resulting trees all have the same type, return them instead of the original ones.
*/
def harmonize(trees: List[Tree])(implicit ctx: Context): List[Tree] = {
def adapt(tree: Tree, pt: Type): Tree = tree match {
case cdef: CaseDef => tpd.cpy.CaseDef(cdef)(body = adapt(cdef.body, pt))
case _ => adaptInterpolated(tree, pt)
def adaptDeep(tree: Tree, pt: Type): Tree = tree match {
case cdef: CaseDef => tpd.cpy.CaseDef(cdef)(body = adaptDeep(cdef.body, pt))
case _ => adapt(tree, pt)
}
if (ctx.isAfterTyper) trees else harmonizeWith(trees)(_.tpe, adapt)
if (ctx.isAfterTyper) trees else harmonizeWith(trees)(_.tpe, adaptDeep)
}

/** Apply a transformation `harmonize` on the results of operation `op`.
Expand Down
7 changes: 5 additions & 2 deletions compiler/src/dotty/tools/dotc/typer/ErrorReporting.scala
Original file line number Diff line number Diff line change
Expand Up @@ -120,9 +120,12 @@ object ErrorReporting {
val found1 = dropJavaMethod(found)
val expected1 = dropJavaMethod(expected)
if ((found1 eq found) != (expected eq expected1) && (found1 <:< expected1))
"\n(Note that Scala's and Java's representation of this type differs)"
i"""
|(Note that Scala's and Java's representation of this type differs)"""
else if (ctx.settings.explainTypes.value)
"\n" + ctx.typerState.show + "\n" + TypeComparer.explained((found <:< expected)(_))
i"""
|${ctx.typerState.constraint}
|${TypeComparer.explained((found <:< expected)(_))}"""
else
""
}
Expand Down
7 changes: 4 additions & 3 deletions compiler/src/dotty/tools/dotc/typer/Implicits.scala
Original file line number Diff line number Diff line change
Expand Up @@ -768,7 +768,7 @@ trait Implicits { self: Typer =>
case result: SearchSuccess =>
result.tstate.commit()
implicits.println(i"success: $result")
implicits.println(i"committing ${result.tstate.constraint} yielding ${ctx.typerState.constraint} ${ctx.typerState.hashesStr}")
implicits.println(i"committing ${result.tstate.constraint} yielding ${ctx.typerState.constraint} in ${ctx.typerState}")
result
case result: SearchFailure if result.isAmbiguous =>
val deepPt = pt.deepenProto
Expand Down Expand Up @@ -828,11 +828,12 @@ trait Implicits { self: Typer =>
def typedImplicit(cand: Candidate, contextual: Boolean)(implicit ctx: Context): SearchResult = track("typedImplicit") { trace(i"typed implicit ${cand.ref}, pt = $pt, implicitsEnabled == ${ctx.mode is ImplicitsEnabled}", implicits, show = true) {
val ref = cand.ref
var generated: Tree = tpd.ref(ref).withPos(pos.startPos)
val locked = ctx.typerState.ownedVars
if (!argument.isEmpty)
generated = typedUnadapted(
untpd.Apply(untpd.TypedSplice(generated), untpd.TypedSplice(argument) :: Nil),
pt)
val generated1 = adapt(generated, pt)
pt, locked)
val generated1 = adapt(generated, pt, locked)
lazy val shadowing =
typed(untpd.Ident(cand.implicitRef.implicitName) withPos pos.toSynthetic, funProto)(
nestedContext().addMode(Mode.ImplicitShadowing).setExploreTyperState())
Expand Down
Loading