Skip to content

Commit ea640a3

Browse files
committed
Additions needed to support implicits.
Still to do: - properly account for bounded wildcard types - set up scheme for nested diagnostics buffers.
1 parent 17ef71d commit ea640a3

11 files changed

+485
-42
lines changed

src/dotty/tools/dotc/core/Contexts.scala

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import ast.Trees._
1616
import ast.untpd
1717
import util.{FreshNameCreator, SimpleMap}
1818
import typer._
19+
import Implicits.ContextualImplicits
1920
import config.Settings._
2021
import reporting._
2122
import collection.mutable
@@ -140,6 +141,11 @@ object Contexts {
140141
protected def reporter_=(reporter: Reporter) = _reporter = reporter
141142
def reporter: Reporter = _reporter
142143

144+
/** The current compiler-run specific Info */
145+
private[this] var _runInfo: RunInfo = _
146+
protected def runInfo_=(runInfo: RunInfo) = _runInfo = runInfo
147+
def runInfo: RunInfo = _runInfo
148+
143149
/** An optional diagostics buffer than is used by some checking code
144150
* to provide more information in the buffer if it exists.
145151
*/
@@ -159,7 +165,23 @@ object Contexts {
159165
_typeComparer
160166
}
161167

162-
/** If -Ydebug is on, the top of the stack trace where this context
168+
/** The new implicit references that are introduces by this scope */
169+
private var implicitsCache: ContextualImplicits = null
170+
def implicits: ContextualImplicits = {
171+
if (implicitsCache == null )
172+
implicitsCache = {
173+
val implicitRefs: Set[TermRef] =
174+
if (isClassDefContext) owner.thisType.implicitMembers
175+
else if (isImportContext) importInfo.importedImplicits
176+
else if (isNonEmptyScopeContext) scope.implicitDecls
177+
else Set()
178+
if (implicitRefs.isEmpty) outer.implicits
179+
else new ContextualImplicits(implicitRefs, outer.implicits.ctx)
180+
}
181+
implicitsCache
182+
}
183+
184+
/** If -Ydebug is on, the top of the stack trace where this context
163185
* was created, otherwise `null`.
164186
*/
165187
private var creationTrace: Array[StackTraceElement] = _
@@ -180,6 +202,18 @@ object Contexts {
180202
println("=== end context creation trace ===")
181203
}
182204

205+
/** Is this a context for the members of a class definition? */
206+
def isClassDefContext: Boolean =
207+
owner.isClass && (owner ne outer.owner)
208+
209+
/** Is this a context that introduces an import clause? */
210+
def isImportContext: Boolean =
211+
(this ne NoContext) && (this.importInfo ne outer.importInfo)
212+
213+
/** Is this a context that introduces a non-empty scope? */
214+
def isNonEmptyScopeContext: Boolean =
215+
(this.scope ne outer.scope) && this.scope.nonEmpty
216+
183217
/** Leave message in diagnostics buffer if it exists */
184218
def diagnose(str: => String) =
185219
for (sb <- diagnostics) {
@@ -224,6 +258,7 @@ object Contexts {
224258
.withSettings(sstate)
225259
// tree is not preserved in condensed
226260
.withReporter(reporter)
261+
.withRunInfo(runInfo)
227262
.withDiagnostics(diagnostics)
228263
.withMoreProperties(moreProperties)
229264
_condensed
@@ -235,6 +270,7 @@ object Contexts {
235270
def fresh: FreshContext = {
236271
val newctx = super.clone.asInstanceOf[FreshContext]
237272
newctx.outer = this
273+
newctx.implicitsCache = null
238274
newctx.setCreationTrace()
239275
newctx
240276
}
@@ -266,6 +302,7 @@ object Contexts {
266302
def withTyper(typer: Typer): this.type = { this.typer = typer; this.scope = typer.scope; this }
267303
def withImportInfo(importInfo: ImportInfo): this.type = { this.importInfo = importInfo; this }
268304
def withReporter(reporter: Reporter): this.type = { this.reporter = reporter; this }
305+
def withRunInfo(runInfo: RunInfo): this.type = { this.runInfo = runInfo; this }
269306
def withDiagnostics(diagnostics: Option[StringBuilder]): this.type = { this.diagnostics = diagnostics; this }
270307
def withMoreProperties(moreProperties: Map[String, Any]): this.type = { this.moreProperties = moreProperties; this }
271308

@@ -278,6 +315,7 @@ object Contexts {
278315

279316
def withDebug = withSetting(base.settings.debug, true)
280317
def withImplicitsDisabled: this.type = ???
318+
def silent: this.type = ???
281319
}
282320

283321
/** A class defining the initial context with given context base
@@ -294,8 +332,11 @@ object Contexts {
294332
sstate = settings.defaultState
295333
tree = untpd.EmptyTree
296334
reporter = new ConsoleReporter()(this)
335+
runInfo = new RunInfo
297336
diagnostics = None
298337
moreProperties = Map.empty
338+
339+
override val implicits = new ContextualImplicits(Set(), NoContext)(this)
299340
}
300341

301342
object NoContext extends Context {
@@ -418,6 +459,9 @@ object Contexts {
418459
val theBase = new ContextBase // !!! DEBUG, so that we can use a minimal context for reporting even in code that normallly cannot access a context
419460
}
420461

462+
/** Info that changes on each compiler run */
463+
class RunInfo(implicit val ctx: Context) extends ImplicitRunInfo
464+
421465
/** Initial size of superId table */
422466
private final val InitialSuperIdsSize = 4096
423467

src/dotty/tools/dotc/core/Flags.scala

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -203,18 +203,14 @@ object Flags {
203203
final val TypeParam = Param.toTypeFlags
204204

205205
/** Labeled with `implicit` modifier (implicit value) */
206-
final val Implicit = termFlag(9, "implicit")
207-
208-
/** A trait */
209-
final val Trait = typeFlag(9, "<trait>")
206+
final val ImplicitCommon = commonFlag(9, "implicit")
207+
final val Implicit = ImplicitCommon.toTermFlags
210208

211209
/** Labeled with `lazy` (a lazy val). */
212210
final val Lazy = termFlag(10, "lazy")
213211

214-
/** A trait that has only abstract methods as members
215-
* (and therefore can be represented by a Java interface
216-
*/
217-
final val Interface = typeFlag(10, "interface")
212+
/** A trait */
213+
final val Trait = typeFlag(10, "<trait>")
218214

219215
/** A value or variable accessor (getter or setter) */
220216
final val Accessor = termFlag(11, "<accessor>")
@@ -273,6 +269,11 @@ object Flags {
273269
/** Method is a label. */
274270
final val Label = termFlag(22, "<label>")
275271

272+
/** A trait that has only abstract methods as members
273+
* (and therefore can be represented by a Java interface
274+
*/
275+
final val Interface = typeFlag(22, "interface")
276+
276277
/** Labeled with `abstract` modifier (an abstract class)
277278
* Note: You should never see Abstract on any symbol except a class.
278279
* Note: the flag counts as common, because it can be combined with OVERRIDE in a term.
@@ -380,7 +381,7 @@ object Flags {
380381
final val FromStartFlags =
381382
AccessFlags | Module | Package | Deferred | Param | Scala2ExistentialCommon | Touched |
382383
Static | CovariantCommon | ContravariantCommon | ExpandedName | AccessorOrSealed | Frozen |
383-
Erroneous
384+
Erroneous | ImplicitCommon
384385

385386
assert(FromStartFlags.isTermFlags && FromStartFlags.isTypeFlags)
386387
// TODO: Should check that FromStartFlags do not change in completion

src/dotty/tools/dotc/core/Scopes.scala

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ package dotty.tools.dotc
77
package core
88

99
import Symbols._
10+
import Types.{TermRef, NoPrefix}
11+
import Flags.Implicit
1012
import Names._
1113
import Periods._
1214
import Decorators._
@@ -109,6 +111,8 @@ object Scopes {
109111
syms
110112
}
111113

114+
def implicitDecls(implicit ctx: Context): Set[TermRef] = Set()
115+
112116
final def toText(printer: Printer): Text = printer.toText(this)
113117
}
114118

@@ -283,6 +287,17 @@ object Scopes {
283287
elemsCache
284288
}
285289

290+
override def implicitDecls(implicit ctx: Context): Set[TermRef] = {
291+
var irefs: Set[TermRef] = Set()
292+
var e = lastEntry
293+
while (e ne null) {
294+
if (e.sym is Implicit)
295+
irefs += TermRef(NoPrefix, e.sym.name.asTermName).withDenot(e.sym.denot)
296+
e = e.prev
297+
}
298+
irefs
299+
}
300+
286301
/** Vanilla scope - symbols are stored in declaration order.
287302
*/
288303
final def sorted: List[Symbol] = toList

src/dotty/tools/dotc/core/SymDenotations.scala

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -30,10 +30,6 @@ trait SymDenotations { this: Context =>
3030
result.validFor = stablePeriod
3131
result
3232
}
33-
34-
def lookup(name: Name): PreDenotation =
35-
if (owner.isClass && (owner ne outer.owner)) owner.asClass.membersNamed(name)
36-
else scope.denotsNamed(name)
3733
}
3834
object SymDenotations {
3935

@@ -700,7 +696,7 @@ object SymDenotations {
700696
* because the latter does not ensure that the `parentDenots` key
701697
* is up-to-date, which might lead to invalid caches later on.
702698
*/
703-
private def classParents(implicit ctx: Context) = {
699+
def classParents(implicit ctx: Context) = {
704700
val ps = classInfo.classParents
705701
if (parentDenots == null) parentDenots = ps map (_.denot)
706702
ps

src/dotty/tools/dotc/core/TyperState.scala

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ class TyperState extends DotClass {
2323
def diagnostics_=(ds: List[Diagnostic]): Unit = unsupported("diagnostics_=")
2424

2525
def fresh: TyperState = this
26+
27+
def copyFrom(tp: TyperState): Unit = unsupported("copyFrom")
2628
}
2729

2830
class MutableTyperState (previous: TyperState) extends TyperState {
@@ -40,4 +42,11 @@ class MutableTyperState (previous: TyperState) extends TyperState {
4042
override def diagnostics_=(ds: List[Diagnostic]) = myDiagnostics = ds
4143

4244
override def fresh: TyperState = new MutableTyperState(this)
45+
46+
override def copyFrom(state: TyperState): Unit = {
47+
constraint = state.constraint
48+
undetVars = state.undetVars
49+
// todo: do something about diagnostics (put reporter in state?)
50+
}
51+
4352
}

src/dotty/tools/dotc/core/Types.scala

Lines changed: 78 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ object Types {
5959
* | +- TypeBounds
6060
* | +- ExprType
6161
* | +- AnnotatedType
62+
* | +- TypeVar
6263
* |
6364
* +- GroundType -+- AndType
6465
* +- OrType
@@ -165,6 +166,10 @@ object Types {
165166
*/
166167
final def forallParts(p: Type => Boolean): Boolean = !existsPart(!p(_))
167168

169+
/** The parts of this type which are type or term refs */
170+
final def namedParts(implicit ctx: Context): Set[NamedType] =
171+
new PartsAccumulator().apply(Set(), this)
172+
168173
/** Map function over elements of an AndType, rebuilding with & */
169174
def mapAnd(f: Type => Type)(implicit ctx: Context): Type = thisInstance match {
170175
case AndType(tp1, tp2) => tp1.mapAnd(f) & tp2.mapAnd(f)
@@ -213,6 +218,21 @@ object Types {
213218
NoSymbol
214219
}
215220

221+
/** The least (wrt <:<) set of class symbols of which this type is a subtype
222+
*/
223+
final def classSymbols(implicit ctx: Context): Set[ClassSymbol] = this match {
224+
case tp: ClassInfo =>
225+
Set(tp.cls)
226+
case tp: TypeProxy =>
227+
tp.underlying.classSymbols
228+
case AndType(l, r) =>
229+
l.classSymbols | r.classSymbols
230+
case OrType(l, r) =>
231+
l.classSymbols & r.classSymbols
232+
case _ =>
233+
Set()
234+
}
235+
216236
/** The term symbol associated with the type */
217237
final def termSymbol(implicit ctx: Context): Symbol = this match {
218238
case tp: TermRef => tp.symbol
@@ -399,6 +419,13 @@ object Types {
399419
final def typeMembers(implicit ctx: Context): Set[SingleDenotation] =
400420
memberNames(typeNameFilter).map(member(_).asInstanceOf[SingleDenotation])
401421

422+
/** The set of implicit members of this type */
423+
final def implicitMembers(implicit ctx: Context): Set[TermRef] =
424+
memberNames(implicitFilter)
425+
.flatMap(name => member(name)
426+
.altsWith(_ is Implicit)
427+
.map(TermRef(this, name.asTermName).withDenot(_)))
428+
402429
/** The info of `sym`, seen as a member of this type. */
403430
final def memberInfo(sym: Symbol)(implicit ctx: Context): Type =
404431
sym.info.asSeenFrom(this, sym.owner)
@@ -572,6 +599,11 @@ object Types {
572599
final def bounds(implicit ctx: Context): TypeBounds = this match {
573600
case tp: TypeBounds => tp
574601
case ci: ClassInfo => TypeAlias(ci.typeConstructor)
602+
case wc: WildcardType =>
603+
wc.optBounds match {
604+
case bounds: TypeBounds => bounds
605+
case NoType => TypeBounds.empty
606+
}
575607
case _ => TypeAlias(this)
576608
}
577609

@@ -1728,7 +1760,8 @@ object Types {
17281760

17291761
/** An annotated type tpe @ annot */
17301762
case class AnnotatedType(annot: Annotation, tpe: Type)
1731-
extends UncachedProxyType with ValueType { // todo: cache them?
1763+
extends UncachedProxyType with ValueType {
1764+
// todo: cache them? but this makes only sense if annotations and trees are also cached.
17321765
override def underlying(implicit ctx: Context): Type = tpe
17331766
def derivedAnnotatedType(annot: Annotation, tpe: Type) =
17341767
if ((annot eq this.annot) && (tpe eq this.tpe)) this
@@ -1761,7 +1794,16 @@ object Types {
17611794

17621795
object ErrorType extends ErrorType
17631796

1764-
case object WildcardType extends UncachedGroundType
1797+
/** Wildcard type, possibly with bounds */
1798+
abstract case class WildcardType(optBounds: Type) extends CachedGroundType {
1799+
override def computeHash = doHash(optBounds)
1800+
}
1801+
1802+
final class CachedWildcardType(optBounds: Type) extends WildcardType(optBounds)
1803+
1804+
object WildcardType extends WildcardType(NoType) {
1805+
def apply(bounds: TypeBounds)(implicit ctx: Context) = unique(new CachedWildcardType(bounds))
1806+
}
17651807

17661808
/** An extractor for single abstract method types.
17671809
* A type is a SAM type if it is a reference to a class or trait, which
@@ -1892,6 +1934,22 @@ object Types {
18921934
}
18931935
}
18941936

1937+
/** Approximate occurrences of paremter types and uninstantiated typevars
1938+
* by wildcard types
1939+
*/
1940+
class WildApprox(implicit ctx: Context) extends TypeMap {
1941+
override def apply(tp: Type) = tp match {
1942+
case PolyParam(pt, pnum) =>
1943+
WildcardType(apply(pt.paramBounds(pnum)).bounds)
1944+
case MethodParam(mt, pnum) =>
1945+
WildcardType(TypeBounds.upper(apply(mt.paramTypes(pnum))))
1946+
case tp: TypeVar =>
1947+
apply(tp.underlying)
1948+
case _ =>
1949+
mapOver(tp)
1950+
}
1951+
}
1952+
18951953
// ----- TypeAccumulators ----------------------------------------------------
18961954

18971955
abstract class TypeAccumulator[T] extends ((T, Type) => T) {
@@ -1939,6 +1997,19 @@ object Types {
19391997
def apply(x: Boolean, tp: Type) = x || p(tp) || foldOver(x, tp)
19401998
}
19411999

2000+
class PartsAccumulator(implicit ctx: Context) extends TypeAccumulator[Set[NamedType]] {
2001+
def apply(x: Set[NamedType], tp: Type): Set[NamedType] = tp match {
2002+
case tp: NamedType =>
2003+
foldOver(x + tp, tp)
2004+
case tp: ThisType =>
2005+
apply(x, tp.underlying)
2006+
case tp: TypeVar =>
2007+
apply(x, tp.underlying)
2008+
case _ =>
2009+
foldOver(x, tp)
2010+
}
2011+
}
2012+
19422013
// ----- Name Filters --------------------------------------------------
19432014

19442015
/** A name filter selects or discards a member name of a type `pre`.
@@ -1972,6 +2043,11 @@ object Types {
19722043
def apply(pre: Type, name: Name)(implicit ctx: Context): Boolean = true
19732044
}
19742045

2046+
object implicitFilter extends NameFilter {
2047+
def apply(pre: Type, name: Name)(implicit ctx: Context): Boolean =
2048+
(pre member name).hasAltWith(_ is Implicit)
2049+
}
2050+
19752051
// ----- Exceptions -------------------------------------------------------------
19762052

19772053
class TypeError(msg: String) extends Exception(msg)

0 commit comments

Comments
 (0)