diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index 06765608430e..2c620cd3a642 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -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 @@ -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 @@ -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 @@ -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`. */ diff --git a/compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala b/compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala index 43c2410d5bad..51746c5c0020 100644 --- a/compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala +++ b/compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala @@ -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 = { diff --git a/compiler/src/dotty/tools/dotc/typer/Implicits.scala b/compiler/src/dotty/tools/dotc/typer/Implicits.scala index 310c93befda9..85d045542577 100644 --- a/compiler/src/dotty/tools/dotc/typer/Implicits.scala +++ b/compiler/src/dotty/tools/dotc/typer/Implicits.scala @@ -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) @@ -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 => @@ -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) => @@ -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) @@ -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 => { diff --git a/compiler/src/dotty/tools/dotc/typer/ProtoTypes.scala b/compiler/src/dotty/tools/dotc/typer/ProtoTypes.scala index c69b06c872db..f96a0c761503 100644 --- a/compiler/src/dotty/tools/dotc/typer/ProtoTypes.scala +++ b/compiler/src/dotty/tools/dotc/typer/ProtoTypes.scala @@ -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 = @@ -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)) diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala index 60c074f82955..547f132d2066 100644 --- a/compiler/src/dotty/tools/dotc/typer/Typer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala @@ -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)) } @@ -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) } } @@ -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) } @@ -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) diff --git a/tests/pos/implicit-scope.scala b/tests/pos/implicit-scope.scala new file mode 100644 index 000000000000..4c2f71b33c09 --- /dev/null +++ b/tests/pos/implicit-scope.scala @@ -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 ? +} \ No newline at end of file diff --git a/tests/run/implicitFuns.scala b/tests/run/implicitFuns.scala index 508d54c31569..719d5b502847 100644 --- a/tests/run/implicitFuns.scala +++ b/tests/run/implicitFuns.scala @@ -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 } }