Skip to content

Ignore all kinds of ProtoTypes instead of just AppliedProtos #6715

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 6 commits into from
Jun 20, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
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
25 changes: 16 additions & 9 deletions compiler/src/dotty/tools/dotc/core/Types.scala
Original file line number Diff line number Diff line change
Expand Up @@ -440,24 +440,29 @@ object Types {
NoSymbol
}

/** The least (wrt <:<) set of class symbols of which this type is a subtype
/** The least (wrt <:<) set of symbols satisfying the `include` prediacte of which this type is a subtype
*/
final def classSymbols(implicit ctx: Context): List[ClassSymbol] = this match {
final def parentSymbols(include: Symbol => Boolean)(implicit ctx: Context): List[Symbol] = this match {
case tp: ClassInfo =>
tp.cls :: Nil
case tp: TypeRef =>
val sym = tp.symbol
if (sym.isClass) sym.asClass :: Nil else tp.superType.classSymbols
if (include(sym)) sym :: Nil else tp.superType.parentSymbols(include)
case tp: TypeProxy =>
tp.underlying.classSymbols
tp.underlying.parentSymbols(include)
case AndType(l, r) =>
l.classSymbols | r.classSymbols
l.parentSymbols(include) | r.parentSymbols(include)
case OrType(l, r) =>
l.classSymbols intersect r.classSymbols // TODO does not conform to spec
l.parentSymbols(include) intersect r.parentSymbols(include) // TODO does not conform to spec
case _ =>
Nil
}

/** The least (wrt <:<) set of class symbols of which this type is a subtype
*/
final def classSymbols(implicit ctx: Context): List[ClassSymbol] =
parentSymbols(_.isClass).asInstanceOf

/** The term symbol associated with the type */
@tailrec final def termSymbol(implicit ctx: Context): Symbol = this match {
case tp: TermRef => tp.symbol
Expand Down Expand Up @@ -1244,9 +1249,6 @@ object Types {
case _ => if (isRepeatedParam) this.argTypesHi.head else this
}

/** If this is a FunProto or PolyProto, WildcardType, otherwise this. */
def notApplied: Type = this

// ----- Normalizing typerefs over refined types ----------------------------

/** If this normalizes* to a refinement type that has a refinement for `name` (which might be followed
Expand Down Expand Up @@ -1428,6 +1430,9 @@ object Types {
/** If this is an ignored proto type, its underlying type, otherwise the type itself */
def revealIgnored: Type = this

/** If this is a proto type, WildcardType, otherwise the type itself */
def dropIfProto: Type = this

// ----- Substitutions -----------------------------------------------------

/** Substitute all types that refer in their symbol attribute to
Expand Down Expand Up @@ -1728,6 +1733,8 @@ object Types {
* captures the given context `ctx`.
*/
def withContext(ctx: Context): ProtoType = this

override def dropIfProto = WildcardType
}

/** Implementations of this trait cache the results of `narrow`. */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1363,7 +1363,9 @@ object messages {

val msg: String = {
val more = if (tree.isInstanceOf[tpd.Apply]) " more" else ""
em"${methodSymbol.showLocated} does not take$more parameters"
val meth = methodSymbol
val methStr = if (meth.exists) methodSymbol.showLocated else "expression"
em"$methStr does not take$more parameters"
}

val explanation: String = {
Expand Down
27 changes: 18 additions & 9 deletions compiler/src/dotty/tools/dotc/typer/Implicits.scala
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,7 @@ object Implicits {
*/
class OfTypeImplicits(tp: Type, val companionRefs: TermRefSet)(initctx: Context) extends ImplicitRefs(initctx) {
assert(initctx.typer != null)
implicits.println(i"implicits of type $tp = ${companionRefs.toList}%, %")
@threadUnsafe lazy val refs: List[ImplicitRef] = {
val buf = new mutable.ListBuffer[TermRef]
for (companion <- companionRefs) buf ++= companion.implicitMembers(ImplicitOrImpliedOrGiven)
Expand Down Expand Up @@ -491,13 +492,19 @@ trait ImplicitRunInfo { self: Run =>
object liftToClasses extends TypeMap {
override implicit protected val ctx: Context = liftingCtx
override def stopAtStatic = true

private def isLiftTarget(sym: Symbol) = sym.isClass || sym.isOpaqueAlias

def apply(tp: Type) = tp match {
case tp: TypeRef if !tp.symbol.isClass =>
val pre = tp.prefix
def joinClass(tp: Type, cls: ClassSymbol) =
AndType.make(tp, cls.typeRef.asSeenFrom(pre, cls.owner))
val lead = if (pre eq NoPrefix) defn.AnyType else apply(pre)
(lead /: tp.classSymbols)(joinClass)
case tp: TypeRef =>
if (isLiftTarget(tp.symbol)) tp
else {
val pre = tp.prefix
def joinClass(tp: Type, cls: Symbol) =
AndType.make(tp, cls.typeRef.asSeenFrom(pre, cls.owner))
val lead = if (pre eq NoPrefix) defn.AnyType else apply(pre)
(lead /: tp.parentSymbols(isLiftTarget))(joinClass)
}
case tp: TypeVar =>
apply(tp.underlying)
case tp: AppliedType if !tp.tycon.typeSymbol.isClass =>
Expand All @@ -516,7 +523,7 @@ trait ImplicitRunInfo { self: Run =>

// todo: compute implicits directly, without going via companionRefs?
def collectCompanions(tp: Type): TermRefSet = track("computeImplicitScope") {
trace(i"collectCompanions($tp)", implicits) {
trace(i"collectCompanions($tp)", implicitsDetailed) {

def iscopeRefs(t: Type): TermRefSet = implicitScopeCache.get(t) match {
case Some(is) =>
Expand Down Expand Up @@ -575,8 +582,10 @@ trait ImplicitRunInfo { self: Run =>
def computeIScope() = {
val liftedTp = if (isLifted) tp else liftToClasses(tp)
val refs =
if (liftedTp ne tp)
if (liftedTp ne tp) {
implicitsDetailed.println(i"lifted of $tp = $liftedTp")
iscope(liftedTp, isLifted = true).companionRefs
}
else
collectCompanions(tp)
val result = new OfTypeImplicits(tp, refs)(ctx)
Expand Down Expand Up @@ -673,7 +682,7 @@ trait Implicits { self: Typer =>
}

/** Synthesize the tree for `'[T]` for an implicit `scala.quoted.Type[T]`.
* `T` is deeply dealiassed to avoid references to local type aliases.
* `T` is deeply dealiased to avoid references to local type aliases.
*/
lazy val synthesizedTypeTag: SpecialHandler =
(formal, span) => implicit ctx => {
Expand Down
4 changes: 0 additions & 4 deletions compiler/src/dotty/tools/dotc/typer/ProtoTypes.scala
Original file line number Diff line number Diff line change
Expand Up @@ -260,8 +260,6 @@ object ProtoTypes {
if ((args eq this.args) && (resultType eq this.resultType) && (typer eq this.typer)) this
else new FunProto(args, resultType)(typer, isGivenApply)

override def notApplied: Type = WildcardType

/** @return True if all arguments have types.
*/
def allArgTypesAreCurrent()(implicit ctx: Context): Boolean =
Expand Down Expand Up @@ -453,8 +451,6 @@ object ProtoTypes {
if ((targs eq this.targs) && (resType eq this.resType)) this
else PolyProto(targs, resType)

override def notApplied: Type = WildcardType

def map(tm: TypeMap)(implicit ctx: Context): PolyProto =
derivedPolyProto(targs, tm(resultType))

Expand Down
10 changes: 5 additions & 5 deletions compiler/src/dotty/tools/dotc/typer/Typer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -712,7 +712,7 @@ class Typer extends Namer

def typedBlock(tree: untpd.Block, pt: Type)(implicit ctx: Context): Tree = track("typedBlock") {
val (exprCtx, stats1) = typedBlockStats(tree.stats)
val expr1 = typedExpr(tree.expr, pt.notApplied)(exprCtx)
val expr1 = typedExpr(tree.expr, pt.dropIfProto)(exprCtx)
ensureNoLocalRefs(
cpy.Block(tree)(stats1, expr1).withType(expr1.tpe), pt, localSyms(stats1))
}
Expand Down Expand Up @@ -766,7 +766,7 @@ class Typer extends Namer
}
else {
val thenp1 :: elsep1 :: Nil = harmonic(harmonize, pt)(
(tree.thenp :: tree.elsep :: Nil).map(typed(_, pt.notApplied)))
(tree.thenp :: tree.elsep :: Nil).map(typed(_, pt.dropIfProto)))
assignType(cpy.If(tree)(cond1, thenp1, elsep1), thenp1, elsep1)
}
}
Expand Down Expand Up @@ -1068,7 +1068,7 @@ class Typer extends Namer

// Overridden in InlineTyper for inline matches
def typedMatchFinish(tree: untpd.Match, sel: Tree, wideSelType: Type, cases: List[untpd.CaseDef], pt: Type)(implicit ctx: Context): Tree = {
val cases1 = harmonic(harmonize, pt)(typedCases(cases, wideSelType, pt.notApplied))
val cases1 = harmonic(harmonize, pt)(typedCases(cases, wideSelType, pt.dropIfProto))
.asInstanceOf[List[CaseDef]]
assignType(cpy.Match(tree)(sel, cases1), sel, cases1)
}
Expand Down Expand Up @@ -1193,8 +1193,8 @@ class Typer extends Namer

def typedTry(tree: untpd.Try, pt: Type)(implicit ctx: Context): Try = track("typedTry") {
val expr2 :: cases2x = harmonic(harmonize, pt) {
val expr1 = typed(tree.expr, pt.notApplied)
val cases1 = typedCases(tree.cases, defn.ThrowableType, pt.notApplied)
val expr1 = typed(tree.expr, pt.dropIfProto)
val cases1 = typedCases(tree.cases, defn.ThrowableType, pt.dropIfProto)
expr1 :: cases1
}
val finalizer1 = typed(tree.finalizer, defn.UnitType)
Expand Down
30 changes: 30 additions & 0 deletions tests/pos/implicit-scope.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
object A {

object opaques {
opaque type FlagSet = Long
def FlagSet(bits: Long): FlagSet = bits.asInstanceOf // !!!
def toBits(fs: FlagSet): Long = fs
}
val someFlag = FlagSet(1)
type FlagSet = opaques.FlagSet
def FlagSet(bits: Long): FlagSet = opaques.FlagSet(bits)

delegate FlagOps {
def (xs: FlagSet) bits: Long = opaques.toBits(xs)
def (xs: FlagSet) | (ys: FlagSet): FlagSet = FlagSet(xs.bits | ys.bits)
}
}

object B {
type Variance = A.FlagSet

val f: A.FlagSet = A.someFlag
f.bits // OK

val v: Variance = A.someFlag
v.bits // OK, used to fail with: value bits is not a member of B.Variance

A.someFlag.bits // OK
var x = 0
(if (x > 0) A.someFlag else A.someFlag).bits // OK, used to fail with: value bits is not a member of ?
}
2 changes: 1 addition & 1 deletion tests/run/implicitFuns.scala
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ object Test {

def foo(s: String): Stringly[Int] = 42

(if ("".isEmpty) foo("") else foo("")).apply given ""
//(if ("".isEmpty) foo("") else foo("")).apply given "" // does not typecheck
}
}

Expand Down