Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 1d0cdf9

Browse files
committedOct 18, 2022
Add member disambiguation ignoring capture sets
1 parent 550368e commit 1d0cdf9

File tree

5 files changed

+58
-17
lines changed

5 files changed

+58
-17
lines changed
 

‎compiler/src/dotty/tools/dotc/cc/CapturingType.scala

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,10 @@ object CapturingType:
4141
* returned separately by CaptureOps.isBoxed.
4242
*/
4343
def unapply(tp: AnnotatedType)(using Context): Option[(Type, CaptureSet)] =
44-
if ctx.phase == Phases.checkCapturesPhase && tp.annot.symbol == defn.RetainsAnnot then
44+
if ctx.phase == Phases.checkCapturesPhase
45+
&& tp.annot.symbol == defn.RetainsAnnot
46+
&& !ctx.mode.is(Mode.IgnoreCaptures)
47+
then
4548
EventuallyCapturingType.unapply(tp)
4649
else None
4750

‎compiler/src/dotty/tools/dotc/cc/CheckCaptures.scala

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ package cc
55
import core.*
66
import Phases.*, DenotTransformers.*, SymDenotations.*
77
import Contexts.*, Names.*, Flags.*, Symbols.*, Decorators.*
8-
import Types.*, StdNames.*
8+
import Types.*, StdNames.*, Denotations.*
99
import config.Printers.{capt, recheckr}
1010
import config.Config
1111
import ast.{tpd, untpd, Trees}
@@ -289,7 +289,21 @@ class CheckCaptures extends Recheck, SymTransformer:
289289
* and Cr otherwise.
290290
*/
291291
override def recheckSelection(tree: Select, qualType: Type, name: Name)(using Context) = {
292-
val selType = super.recheckSelection(tree, qualType, name)
292+
def disambiguate(denot: Denotation): Denotation = denot match
293+
case MultiDenotation(denot1, denot2) =>
294+
// This case can arise when we try to merge multiple types that have different
295+
// capture sets on some part. For instance an asSeenFrom might produce
296+
// a bi-mapped capture set arising from a substition. Applying the same substitution
297+
// to the same type twice will nevertheless produce different capture setsw which can
298+
// lead to a failure in disambiguation since neither alternative is better than the
299+
// other in a frozen constraint. An example test case is disambiguate-select.scala.
300+
// We address the problem by disambiguating while ignoring all capture sets as a fallback.
301+
withMode(Mode.IgnoreCaptures) {
302+
disambiguate(denot1).meet(disambiguate(denot2), qualType)
303+
}
304+
case _ => denot
305+
306+
val selType = recheckSelection(tree, qualType, name, disambiguate)
293307
val selCs = selType.widen.captureSet
294308
if selCs.isAlwaysEmpty || selType.widen.isBoxedCapturing || qualType.isBoxedCapturing then
295309
selType
@@ -762,6 +776,7 @@ class CheckCaptures extends Recheck, SymTransformer:
762776
override def checkUnit(unit: CompilationUnit)(using Context): Unit =
763777
Setup(preRecheckPhase, thisPhase, recheckDef)
764778
.traverse(ctx.compilationUnit.tpdTree)
779+
//println(i"SETUP:\n${Recheck.addRecheckedTypes.transform(ctx.compilationUnit.tpdTree)}")
765780
withCaptureSetsExplained {
766781
super.checkUnit(unit)
767782
checkSelfTypes(unit.tpdTree)

‎compiler/src/dotty/tools/dotc/core/Mode.scala

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,14 @@ object Mode {
7878
/** Use Scala2 scheme for overloading and implicit resolution */
7979
val OldOverloadingResolution: Mode = newMode(15, "OldOverloadingResolution")
8080

81+
/** Treat CapturingTypes as plain AnnotatedTypes even in phase =Ycc.
82+
* Reuses the value of OldOverloadingResolution to save Mode bits.
83+
* This is OK since OldOverloadingResolution only affects implicit search, which
84+
* is done during phases Typer and Inlinig, and IgnoreCaptures only has an
85+
* effect during phase CheckCaptures.
86+
*/
87+
val IgnoreCaptures = OldOverloadingResolution
88+
8189
/** Allow hk applications of type lambdas to wildcard arguments;
8290
* used for checking that such applications do not normally arise
8391
*/

‎compiler/src/dotty/tools/dotc/transform/Recheck.scala

Lines changed: 21 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ package transform
44

55
import core.*
66
import Symbols.*, Contexts.*, Types.*, ContextOps.*, Decorators.*, SymDenotations.*
7-
import Flags.*, SymUtils.*, NameKinds.*
7+
import Flags.*, SymUtils.*, NameKinds.*, Denotations.Denotation
88
import ast.*
99
import Names.Name
1010
import Phases.Phase
@@ -23,7 +23,7 @@ import reporting.trace
2323
import annotation.constructorOnly
2424

2525
object Recheck:
26-
import tpd.Tree
26+
import tpd.*
2727

2828
/** A flag used to indicate that a ParamAccessor has been temporarily made not-private
2929
* Only used at the start of the Recheck phase, reset at its end.
@@ -36,6 +36,13 @@ object Recheck:
3636
/** Attachment key for rechecked types of TypeTrees */
3737
val RecheckedType = Property.Key[Type]
3838

39+
val addRecheckedTypes = new TreeMap:
40+
override def transform(tree: Tree)(using Context): Tree =
41+
val tree1 = super.transform(tree)
42+
tree.getAttachment(RecheckedType) match
43+
case Some(tpe) => tree1.withType(tpe)
44+
case None => tree1
45+
3946
extension (sym: Symbol)
4047

4148
/** Update symbol's info to newInfo from prevPhase.next to lastPhase.
@@ -129,7 +136,7 @@ abstract class Recheck extends Phase, SymTransformer:
129136
def keepType(tree: Tree): Boolean = keepAllTypes
130137

131138
/** Constant-folded rechecked type `tp` of tree `tree` */
132-
private def constFold(tree: Tree, tp: Type)(using Context): Type =
139+
protected def constFold(tree: Tree, tp: Type)(using Context): Type =
133140
val tree1 = tree.withType(tp)
134141
val tree2 = ConstFold(tree1)
135142
if tree2 ne tree1 then tree2.tpe else tp
@@ -141,17 +148,23 @@ abstract class Recheck extends Phase, SymTransformer:
141148
val Select(qual, name) = tree
142149
recheckSelection(tree, recheck(qual).widenIfUnstable, name)
143150

144-
/** Keep the symbol of the `select` but re-infer its type */
145-
def recheckSelection(tree: Select, qualType: Type, name: Name)(using Context) =
151+
def recheckSelection(tree: Select, qualType: Type, name: Name,
152+
sharpen: Denotation => Denotation)(using Context): Type =
146153
if name.is(OuterSelectName) then tree.tpe
147154
else
148155
//val pre = ta.maybeSkolemizePrefix(qualType, name)
149-
val mbr = qualType.findMember(name, qualType,
150-
excluded = if tree.symbol.is(Private) then EmptyFlags else Private
151-
).suchThat(tree.symbol == _)
156+
val mbr = sharpen(
157+
qualType.findMember(name, qualType,
158+
excluded = if tree.symbol.is(Private) then EmptyFlags else Private
159+
)).suchThat(tree.symbol == _)
152160
constFold(tree, qualType.select(name, mbr))
153161
//.showing(i"recheck select $qualType . $name : ${mbr.info} = $result")
154162

163+
164+
/** Keep the symbol of the `select` but re-infer its type */
165+
def recheckSelection(tree: Select, qualType: Type, name: Name)(using Context): Type =
166+
recheckSelection(tree, qualType, name, sharpen = identity)
167+
155168
def recheckBind(tree: Bind, pt: Type)(using Context): Type = tree match
156169
case Bind(name, body) =>
157170
recheck(body, pt)
@@ -444,12 +457,6 @@ abstract class Recheck extends Phase, SymTransformer:
444457

445458
/** Show tree with rechecked types instead of the types stored in the `.tpe` field */
446459
override def show(tree: untpd.Tree)(using Context): String =
447-
val addRecheckedTypes = new TreeMap:
448-
override def transform(tree: Tree)(using Context): Tree =
449-
val tree1 = super.transform(tree)
450-
tree.getAttachment(RecheckedType) match
451-
case Some(tpe) => tree1.withType(tpe)
452-
case None => tree1
453460
atPhase(thisPhase) {
454461
super.show(addRecheckedTypes.transform(tree.asInstanceOf[tpd.Tree]))
455462
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import collection.mutable
2+
class Suppression:
3+
def matches(f: SourceFile): Boolean = ???
4+
class SourceFile
5+
private val mySuppressions: mutable.LinkedHashMap[SourceFile, mutable.ListBuffer[Suppression]] = mutable.LinkedHashMap.empty
6+
7+
def test(f: SourceFile) =
8+
mySuppressions.getOrElse(f, Nil).find(_.matches(f))

0 commit comments

Comments
 (0)
Please sign in to comment.