Skip to content

Commit e4c4e0a

Browse files
authored
Merge pull request #6071 from dotty-staging/fix-impl-res2
Change implicit resolution rule wrt implicit parameters
2 parents 1762f23 + 31ac2ac commit e4c4e0a

16 files changed

+277
-75
lines changed

compiler/src/dotty/tools/dotc/config/Printers.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ object Printers {
1717
val checks: Printer = noPrinter
1818
val config: Printer = noPrinter
1919
val cyclicErrors: Printer = noPrinter
20-
val debug = noPrinter // no type annotion here to force inlining
20+
val debug = noPrinter // no type annotation here to force inlining
2121
val derive: Printer = noPrinter
2222
val dottydoc: Printer = noPrinter
2323
val exhaustivity: Printer = noPrinter

compiler/src/dotty/tools/dotc/config/ScalaSettings.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ class ScalaSettings extends Settings.SettingGroup {
7070
val XprintTypes: Setting[Boolean] = BooleanSetting("-Xprint-types", "Print tree types (debugging option).")
7171
val XprintDiff: Setting[Boolean] = BooleanSetting("-Xprint-diff", "Print changed parts of the tree since last print.")
7272
val XprintDiffDel: Setting[Boolean] = BooleanSetting("-Xprint-diff-del", "Print changed parts of the tree since last print including deleted parts.")
73+
val XprintInline: Setting[Boolean] = BooleanSetting("-Xprint-inline", "Show where inlined code comes from")
7374
val Xprompt: Setting[Boolean] = BooleanSetting("-Xprompt", "Display a prompt after each error (debugging option).")
7475
val XmainClass: Setting[String] = StringSetting("-Xmain-class", "path", "Class for manifest's Main-Class entry (only useful with -d <jar>)", "")
7576
val XnoValueClasses: Setting[Boolean] = BooleanSetting("-Xno-value-classes", "Do not use value classes. Helps debugging.")
@@ -157,7 +158,6 @@ class ScalaSettings extends Settings.SettingGroup {
157158
val YexplainLowlevel: Setting[Boolean] = BooleanSetting("-Yexplain-lowlevel", "When explaining type errors, show types at a lower level.")
158159
val YnoDoubleBindings: Setting[Boolean] = BooleanSetting("-Yno-double-bindings", "Assert no namedtype is bound twice (should be enabled only if program is error-free).")
159160
val YshowVarBounds: Setting[Boolean] = BooleanSetting("-Yshow-var-bounds", "Print type variables with their bounds")
160-
val YshowNoInline: Setting[Boolean] = BooleanSetting("-Yshow-no-inline", "Show inlined code without the 'inlined from' info")
161161

162162
val YnoDecodeStacktraces: Setting[Boolean] = BooleanSetting("-Yno-decode-stacktraces", "Show raw StackOverflow stacktraces, instead of decoding them into triggering operations.")
163163

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1558,7 +1558,7 @@ object SymDenotations {
15581558
case p :: parents1 =>
15591559
p.classSymbol match {
15601560
case pcls: ClassSymbol => builder.addAll(pcls.baseClasses)
1561-
case _ => assert(isRefinementClass || ctx.mode.is(Mode.Interactive), s"$this has non-class parent: $p")
1561+
case _ => assert(isRefinementClass || p.isError || ctx.mode.is(Mode.Interactive), s"$this has non-class parent: $p")
15621562
}
15631563
traverse(parents1)
15641564
case nil =>

compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -417,7 +417,7 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) {
417417
"[" ~ toTextGlobal(elems, ",") ~ " : " ~ toText(elemtpt) ~ "]"
418418
case tree @ Inlined(call, bindings, body) =>
419419
(("/* inlined from " ~ (if (call.isEmpty) "outside" else toText(call)) ~ " */ ") `provided`
420-
!homogenizedView && !ctx.settings.YshowNoInline.value) ~
420+
!homogenizedView && ctx.settings.XprintInline.value) ~
421421
blockText(bindings :+ body)
422422
case tpt: untpd.DerivedTypeTree =>
423423
"<derived typetree watching " ~ summarized(toText(tpt.watched)) ~ ">"

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

Lines changed: 11 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1367,9 +1367,6 @@ trait Applications extends Compatibility { self: Typer with Dynamic =>
13671367
(flip(tp1) relaxed_<:< flip(tp2)) || viewExists(tp1, tp2)
13681368
}
13691369

1370-
// # skipped implicit parameters in tp1 - # skipped implicit parameters in tp2
1371-
var implicitBalance: Int = 0
1372-
13731370
/** Widen the result type of synthetic implied methods from the implementation class to the
13741371
* type that's implemented. Example
13751372
*
@@ -1404,12 +1401,11 @@ trait Applications extends Compatibility { self: Typer with Dynamic =>
14041401
}
14051402

14061403
/** Drop any implicit parameter section */
1407-
def stripImplicit(tp: Type, weight: Int): Type = tp match {
1404+
def stripImplicit(tp: Type): Type = tp match {
14081405
case mt: MethodType if mt.isImplicitMethod =>
1409-
implicitBalance += mt.paramInfos.length * weight
1410-
resultTypeApprox(mt)
1406+
stripImplicit(resultTypeApprox(mt))
14111407
case pt: PolyType =>
1412-
pt.derivedLambdaType(pt.paramNames, pt.paramInfos, stripImplicit(pt.resultType, weight))
1408+
pt.derivedLambdaType(pt.paramNames, pt.paramInfos, stripImplicit(pt.resultType))
14131409
case _ =>
14141410
tp
14151411
}
@@ -1432,18 +1428,16 @@ trait Applications extends Compatibility { self: Typer with Dynamic =>
14321428

14331429
val fullType1 = widenImplied(alt1.widen, alt1)
14341430
val fullType2 = widenImplied(alt2.widen, alt2)
1435-
val strippedType1 = stripImplicit(fullType1, -1)
1436-
val strippedType2 = stripImplicit(fullType2, +1)
1431+
val strippedType1 = stripImplicit(fullType1)
1432+
val strippedType2 = stripImplicit(fullType2)
14371433

14381434
val result = compareWithTypes(strippedType1, strippedType2)
1439-
if (result != 0 || !ctx.typerState.test(implicit ctx => strippedType1 =:= strippedType2))
1440-
result
1441-
else if (implicitBalance != 0)
1442-
-implicitBalance.signum
1443-
else if ((strippedType1 `ne` fullType1) || (strippedType2 `ne` fullType2))
1444-
compareWithTypes(fullType1, fullType2)
1445-
else
1446-
0
1435+
if (result != 0) result
1436+
else if (strippedType1 eq fullType1)
1437+
if (strippedType2 eq fullType2) 0 // no implicits either side: its' a draw
1438+
else 1 // prefer 1st alternative with no implicits
1439+
else if (strippedType2 eq fullType2) -1 // prefer 2nd alternative with no implicits
1440+
else compareWithTypes(fullType1, fullType2) // continue by comparing implicits parameters
14471441
}}
14481442

14491443
def narrowMostSpecific(alts: List[TermRef])(implicit ctx: Context): List[TermRef] = track("narrowMostSpecific") {

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

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2597,7 +2597,10 @@ class Typer extends Namer
25972597
if (arg.tpe.isError) Nil else untpd.NamedArg(pname, untpd.TypedSplice(arg)) :: Nil
25982598
}
25992599
tryEither { implicit ctx =>
2600-
typed(untpd.Apply(untpd.TypedSplice(tree), namedArgs), pt, locked)
2600+
val app = cpy.Apply(tree)(untpd.TypedSplice(tree), namedArgs)
2601+
if (wtp.isContextual) app.pushAttachment(untpd.ApplyGiven, ())
2602+
typr.println(i"try with default implicit args $app")
2603+
typed(app, pt, locked)
26012604
} { (_, _) =>
26022605
issueErrors()
26032606
}

docs/docs/reference/changed-features/implicit-resolution.md

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -114,11 +114,9 @@ affect implicits on the language level.
114114
An alternative A is _more specific_ than an alternative B if
115115

116116
- the relative weight of A over B is greater than the relative weight of B over A, or
117-
- the relative weights are the same, and the returned types of A and B are
118-
unifiable, and A takes more inferable parameters than B, or
119-
- the relative weights and the number of inferable parameters are the same, and
120-
the returned types of A and B are unifiable, and
121-
A is more specific than B if all inferable parameters in either alternative are
117+
- the relative weights are the same, and A takes no implicit parameters but B does, or
118+
- the relative weights are the same, both A and B take implicit parameters, and
119+
A is more specific than B if all implicit parameters in either alternative are
122120
replaced by regular parameters.
123121

124122
[//]: # todo: expand with precise rules

tests/pos/i5978.scala

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -63,14 +63,18 @@ package p3 {
6363
import implied TextParser._
6464
import TextParser._
6565

66-
val tp_v: TokenParser[Char, Position[CharSequence]] = TextParser.TP
67-
val tp_i = the[TokenParser[Char, Position[CharSequence]]]
68-
implicit val co_i: Conversion[Char, Position[CharSequence]] = the[Conversion[Char, Position[CharSequence]]]
69-
val co_x : Position[CharSequence] = 'x'
66+
val co_i: Conversion[Char, Position[CharSequence]] = the[Conversion[Char, Position[CharSequence]]]
7067

7168
{
72-
implied XXX for Conversion[Char, Position[CharSequence]] = co_i
73-
val co_y : Position[CharSequence] = 'x'
69+
val tp_v: TokenParser[Char, Position[CharSequence]] = TextParser.TP
70+
val tp_i = the[TokenParser[Char, Position[CharSequence]]]
71+
implied for Conversion[Char, Position[CharSequence]] = co_i
72+
val co_x : Position[CharSequence] = 'x'
73+
74+
{
75+
implied XXX for Conversion[Char, Position[CharSequence]] = co_i
76+
val co_y : Position[CharSequence] = 'x'
77+
}
7478
}
7579
}
7680
}

tests/run/implicit-functors.check

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
functorId
2+
funcorConst

tests/run/implicit-functors.scala

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
object Utils {
2+
type Id[t] = t
3+
type Const[c] = [t] => c
4+
}
5+
6+
import Utils._
7+
8+
class Instances[F[_[_]], T[_]]
9+
10+
trait Functor[F[_]]
11+
12+
object Functor {
13+
implicit val functorId: Functor[Id] = { println("functorId"); null }
14+
implicit def functorGen[F[_]](implicit inst: Instances[Functor, F]): Functor[F] = { println("funcorGen"); null }
15+
implicit def functorConst[T]: Functor[Const[T]] = { println("funcorConst"); null }
16+
}
17+
18+
case class Sm[A](value: A)
19+
object Sm {
20+
implicit def smInstances[F[_[_]]]: Instances[F, Sm] = { println("smInstances"); null }
21+
}
22+
23+
object Test extends App {
24+
implicitly[Functor[Sm]]
25+
}

0 commit comments

Comments
 (0)