Skip to content

Commit 8115e09

Browse files
committed
Freshing out some more aspects of applications.
1 parent 9e9eb7e commit 8115e09

File tree

4 files changed

+83
-28
lines changed

4 files changed

+83
-28
lines changed

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -229,6 +229,8 @@ object Contexts {
229229
_condensed
230230
}
231231

232+
def implicitsEnabled: Boolean = ???
233+
232234
/** A fresh clone of this context. */
233235
def fresh: FreshContext = {
234236
val newctx = super.clone.asInstanceOf[FreshContext]
@@ -275,6 +277,7 @@ object Contexts {
275277
withSettings(setting.updateIn(sstate, value))
276278

277279
def withDebug = withSetting(base.settings.debug, true)
280+
def withImplicitsDisabled: this.type = ???
278281
}
279282

280283
/** A class defining the initial context with given context base

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

Lines changed: 41 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,20 @@ trait Applications { self: Typer =>
6666
tree
6767
}
6868

69-
def isCompatible(tp: Type, pt: Type): Boolean = ???
69+
def normalize(tp: Type)(implicit ctx: Context) = tp.widen match {
70+
case pt: PolyType => ctx.track(pt).resultType
71+
case mt: MethodType if !mt.isDependent =>
72+
if (mt.isImplicit) mt.resultType
73+
else defn.FunctionType(mt.paramTypes, mt.resultType)
74+
case et: ExprType => et.resultType
75+
case _ => tp
76+
}
77+
78+
def isCompatible(tp: Type, pt: Type)(implicit ctx: Context): Boolean = (
79+
tp <:< pt
80+
|| pt.typeSymbol == defn.ByNameParamClass && tp <:< pt.typeArgs.head
81+
|| viewExists(tp, pt)
82+
)
7083

7184
/**
7285
* @param Arg the type of arguments, could be tpd.Tree, untpd.Tree, or Type
@@ -365,7 +378,7 @@ trait Applications { self: Typer =>
365378
/** Subclass of Application for applicability tests with trees as arguments. */
366379
class ApplicableToTrees(methRef: TermRef, args: List[tpd.Tree], resultType: Type)(implicit ctx: Context)
367380
extends TestApplication(methRef, methRef, args, resultType) with TreeApplication[Type] {
368-
def argType(arg: tpd.Tree): Type = arg.tpe
381+
def argType(arg: tpd.Tree): Type = normalize(arg.tpe)
369382
def treeToArg(arg: tpd.Tree): tpd.Tree = arg
370383
}
371384

@@ -492,7 +505,8 @@ trait Applications { self: Typer =>
492505
new ApplicableToTypes(methRef, args, resultType)(ctx.fresh.withNewTyperState).success
493506

494507
/** Is `tp` a subtype of `pt`? */
495-
def isSubType(tp: Type, pt: Type)(implicit ctx: Context) = (tp <:< pt)(ctx.fresh.withNewTyperState)
508+
def testCompatible(tp: Type, pt: Type)(implicit ctx: Context) =
509+
isCompatible(tp, pt)(ctx.fresh.withNewTyperState)
496510

497511
/** In a set of overloaded applicable alternatives, is `alt1` at least as good as
498512
* `alt2`? `alt1` and `alt2` are nonoverloaded references.
@@ -507,17 +521,17 @@ trait Applications { self: Typer =>
507521

508522
/** Is alternative `alt1` with type `tp1` as specific as alternative
509523
* `alt2` with type `tp2` ? This is the case if `tp2` can be applied to
510-
* `tp1` or `tp2` is a supertype of `tp1`.
524+
* `tp1` (without intervention of implicits) or `tp2' is a supertype of `tp1`.
511525
*/
512526
def isAsSpecific(alt1: TermRef, tp1: Type, alt2: TermRef, tp2: Type): Boolean = tp1 match {
513527
case tp1: PolyType =>
514528
def bounds(tparamRefs: List[TypeRef]) = tp1.paramBounds map (_.substParams(tp1, tparamRefs))
515529
val tparams = ctx.newTypeParams(alt1.symbol.owner, tp1.paramNames, EmptyFlags, bounds)
516530
isAsSpecific(alt1, tp1.instantiate(tparams map (_.symRef)), alt2, tp2)
517531
case tp1: MethodType =>
518-
isApplicableToTypes(alt2, tp1.paramTypes)
532+
isApplicableToTypes(alt2, tp1.paramTypes)(ctx)
519533
case _ =>
520-
isSubType(tp1, tp2)
534+
testCompatible(tp1, tp2)(ctx)
521535
}
522536

523537
val owner1 = alt1.symbol.owner
@@ -547,6 +561,25 @@ trait Applications { self: Typer =>
547561
else /* 1/9 */ winsType1 || /* 2/27 */ !winsType2
548562
}
549563

564+
def narrowMostSpecific(alts: List[TermRef])(implicit ctx: Context): List[TermRef] = (alts: @unchecked) match {
565+
case alt :: alts1 =>
566+
def winner(bestSoFar: TermRef, alts: List[TermRef]): TermRef = alts match {
567+
case alt :: alts1 =>
568+
winner(if (isAsGood(alt, bestSoFar)) alt else bestSoFar, alts1)
569+
case nil =>
570+
bestSoFar
571+
}
572+
val best = winner(alt, alts1)
573+
def asGood(alts: List[TermRef]): List[TermRef] = alts match {
574+
case alt :: alts1 =>
575+
if ((alt eq best) || !isAsGood(alt, best)) asGood(alts1)
576+
else alt :: asGood(alts1)
577+
case nil =>
578+
Nil
579+
}
580+
best :: asGood(alts1)
581+
}
582+
550583
/** Resolve overloaded alternative `alts`, given expected type `pt`. */
551584
def resolveOverloaded(alts: List[TermRef], pt: Type)(implicit ctx: Context): List[TermRef] = {
552585

@@ -574,25 +607,6 @@ trait Applications { self: Typer =>
574607
def narrowByTypes(alts: List[TermRef], argTypes: List[Type], resultType: Type): List[TermRef] =
575608
alts filter (isApplicableToTypes(_, argTypes, resultType))
576609

577-
def narrowMostSpecific(alts: List[TermRef]): List[TermRef] = (alts: @unchecked) match {
578-
case alt :: alts1 =>
579-
def winner(bestSoFar: TermRef, alts: List[TermRef]): TermRef = alts match {
580-
case alt :: alts1 =>
581-
winner(if (isAsGood(alt, bestSoFar)) alt else bestSoFar, alts1)
582-
case nil =>
583-
bestSoFar
584-
}
585-
val best = winner(alt, alts1)
586-
def asGood(alts: List[TermRef]): List[TermRef] = alts match {
587-
case alt :: alts1 =>
588-
if ((alt eq best) || !isAsGood(alt, best)) asGood(alts1)
589-
else alt :: asGood(alts1)
590-
case nil =>
591-
Nil
592-
}
593-
best :: asGood(alts1)
594-
}
595-
596610
val candidates = pt match {
597611
case pt @ FunProtoType(args, resultType) =>
598612
val numArgs = args.length
@@ -636,10 +650,10 @@ trait Applications { self: Typer =>
636650
narrowByTypes(alts, args, resultType)
637651

638652
case tp =>
639-
alts filter (isSubType(_, tp))
653+
alts filter (testCompatible(_, tp))
640654
}
641655

642656
if (isDetermined(candidates)) candidates
643-
else narrowMostSpecific(candidates)
657+
else narrowMostSpecific(candidates)(ctx.fresh.withImplicitsDisabled)
644658
}
645659
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
package dotty.tools
2+
package dotc
3+
package typer
4+
5+
import core._
6+
import ast.{Trees, untpd, tpd, TreeInfo}
7+
import util.Positions._
8+
import Contexts._
9+
import Types._
10+
import Flags._
11+
import Denotations._
12+
import NameOps._
13+
import Symbols._
14+
import Types._
15+
import Decorators._
16+
import Names._
17+
import StdNames._
18+
import Constants._
19+
import Inferencing._
20+
import collection.mutable
21+
22+
trait Implicits { self: Typer =>
23+
24+
import tpd._
25+
26+
def viewExists(from: Type, to: Type)(implicit ctx: Context): Boolean = (
27+
!from.isError
28+
&& !to.isError
29+
&& ctx.implicitsEnabled
30+
&& inferView(EmptyTree, from, to, reportAmbiguous = false) != EmptyTree
31+
)
32+
33+
def inferView(tree: Tree, from: Type, to: Type, reportAmbiguous: Boolean)(implicit ctx: Context): Tree =
34+
inferImplicit(tree, defn.FunctionType(from :: Nil, to), isView = true, reportAmbiguous)
35+
36+
def inferImplicit(tree: Tree, pt: Type, isView: Boolean, reportAmbiguous: Boolean)(implicit ctx: Context): Tree = ???
37+
38+
}

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ object Typer {
4545
}
4646
}
4747

48-
class Typer extends Namer with Applications {
48+
class Typer extends Namer with Applications with Implicits {
4949

5050
import tpd._
5151
import Typer._

0 commit comments

Comments
 (0)