From c03d69f2985802c08d3d6a5e70685c924a111839 Mon Sep 17 00:00:00 2001 From: Nicolas Stucki Date: Wed, 12 Jul 2023 09:52:27 +0200 Subject: [PATCH 01/10] Rename `isFunctionType` to `isFunctionNType` This way we are explicit on the fact that this methods does not cover `PolyFunction` and `ErasedFunction`. --- .../src/dotty/tools/dotc/cc/CheckCaptures.scala | 4 ++-- .../src/dotty/tools/dotc/core/Definitions.scala | 15 ++++++++------- .../src/dotty/tools/dotc/core/TypeComparer.scala | 2 +- compiler/src/dotty/tools/dotc/core/Types.scala | 4 ++-- .../dotty/tools/dotc/transform/BetaReduce.scala | 2 +- .../src/dotty/tools/dotc/typer/Applications.scala | 2 +- .../src/dotty/tools/dotc/typer/Implicits.scala | 4 ++-- .../src/dotty/tools/dotc/typer/Synthesizer.scala | 4 ++-- compiler/src/dotty/tools/dotc/typer/Typer.scala | 12 ++++++------ .../src/dotty/tools/dotc/util/Signatures.scala | 2 +- .../scala/quoted/runtime/impl/QuotesImpl.scala | 2 +- 11 files changed, 27 insertions(+), 26 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/cc/CheckCaptures.scala b/compiler/src/dotty/tools/dotc/cc/CheckCaptures.scala index 380b6ce5fb81..e21da446ce76 100644 --- a/compiler/src/dotty/tools/dotc/cc/CheckCaptures.scala +++ b/compiler/src/dotty/tools/dotc/cc/CheckCaptures.scala @@ -638,7 +638,7 @@ class CheckCaptures extends Recheck, SymTransformer: case expected @ CapturingType(eparent, refs) => CapturingType(recur(eparent), refs, boxed = expected.isBoxed) case expected @ defn.FunctionOf(args, resultType, isContextual) - if defn.isNonRefinedFunction(expected) && defn.isFunctionType(actual) && !defn.isNonRefinedFunction(actual) => + if defn.isNonRefinedFunction(expected) && defn.isFunctionNType(actual) && !defn.isNonRefinedFunction(actual) => val expected1 = toDepFun(args, resultType, isContextual) expected1 case _ => @@ -707,7 +707,7 @@ class CheckCaptures extends Recheck, SymTransformer: val (eargs, eres) = expected.dealias.stripCapturing match case defn.FunctionOf(eargs, eres, _) => (eargs, eres) case expected: MethodType => (expected.paramInfos, expected.resType) - case expected @ RefinedType(_, _, rinfo: MethodType) if defn.isFunctionType(expected) => (rinfo.paramInfos, rinfo.resType) + case expected @ RefinedType(_, _, rinfo: MethodType) if defn.isFunctionNType(expected) => (rinfo.paramInfos, rinfo.resType) case _ => (aargs.map(_ => WildcardType), WildcardType) val aargs1 = aargs.zipWithConserve(eargs) { (aarg, earg) => adapt(aarg, earg, !covariant) } val ares1 = adapt(ares, eres, covariant) diff --git a/compiler/src/dotty/tools/dotc/core/Definitions.scala b/compiler/src/dotty/tools/dotc/core/Definitions.scala index 6ab935a93b77..f517cd2c2b13 100644 --- a/compiler/src/dotty/tools/dotc/core/Definitions.scala +++ b/compiler/src/dotty/tools/dotc/core/Definitions.scala @@ -1709,13 +1709,17 @@ class Definitions { * - scala.FunctionN * - scala.ContextFunctionN */ - def isFunctionType(tp: Type)(using Context): Boolean = + def isFunctionNType(tp: Type)(using Context): Boolean = isNonRefinedFunction(tp.dropDependentRefinement) /** Is `tp` a specialized, refined function type? Either an `ErasedFunction` or a `PolyFunction`. */ def isRefinedFunctionType(tp: Type)(using Context): Boolean = tp.derivesFrom(defn.PolyFunctionClass) || isErasedFunctionType(tp) + /** Is `tp` a specialized, refined function type? Either an `ErasedFunction`. */ + def isErasedFunctionType(tp: Type)(using Context): Boolean = + tp.derivesFrom(defn.ErasedFunctionClass) + /** Returns whether `tp` is an instance or a refined instance of: * - scala.FunctionN * - scala.ContextFunctionN @@ -1723,7 +1727,7 @@ class Definitions { * - PolyFunction */ def isFunctionOrPolyType(tp: Type)(using Context): Boolean = - isFunctionType(tp) || isRefinedFunctionType(tp) + isFunctionNType(tp) || isRefinedFunctionType(tp) private def withSpecMethods(cls: ClassSymbol, bases: List[Name], paramTypes: Set[TypeRef]) = if !ctx.settings.Yscala2Stdlib.value then @@ -1830,7 +1834,7 @@ class Definitions { case tp1 @ RefinedType(parent, nme.apply, mt: MethodType) if isErasedFunctionType(parent) && mt.isContextualMethod => tp1 case tp1 => - if tp1.typeSymbol.name.isContextFunction && isFunctionType(tp1) then tp1 + if tp1.typeSymbol.name.isContextFunction && isFunctionNType(tp1) then tp1 else NoType /** Is `tp` an context function type? */ @@ -1858,13 +1862,10 @@ class Definitions { /* Returns a list of erased booleans marking whether parameters are erased, for a function type. */ def erasedFunctionParameters(tp: Type)(using Context): List[Boolean] = tp.dealias match { case RefinedType(parent, nme.apply, mt: MethodType) => mt.erasedParams - case tp if isFunctionType(tp) => List.fill(functionArity(tp)) { false } + case tp if isFunctionNType(tp) => List.fill(functionArity(tp)) { false } case _ => Nil } - def isErasedFunctionType(tp: Type)(using Context): Boolean = - tp.derivesFrom(defn.ErasedFunctionClass) - /** A whitelist of Scala-2 classes that are known to be pure */ def isAssuredNoInits(sym: Symbol): Boolean = (sym `eq` SomeClass) || isTupleClass(sym) diff --git a/compiler/src/dotty/tools/dotc/core/TypeComparer.scala b/compiler/src/dotty/tools/dotc/core/TypeComparer.scala index 589048b9642c..2aa3e56f60d8 100644 --- a/compiler/src/dotty/tools/dotc/core/TypeComparer.scala +++ b/compiler/src/dotty/tools/dotc/core/TypeComparer.scala @@ -665,7 +665,7 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling case _ => isSubType(info1, info2) - if defn.isFunctionType(tp2) then + if defn.isFunctionNType(tp2) then tp1w.widenDealias match case tp1: RefinedType => return isSubInfo(tp1.refinedInfo, tp2.refinedInfo) diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index 28b0ac02e095..cfc1a2c35acb 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -708,7 +708,7 @@ object Types { } findMember(name, pre, required, excluded) } - + /** The implicit members with given name. If there are none and the denotation * contains private members, also look for shadowed non-private implicits. */ @@ -4071,7 +4071,7 @@ object Types { def addInto(tp: Type): Type = tp match case tp @ AppliedType(tycon, args) if tycon.typeSymbol == defn.RepeatedParamClass => tp.derivedAppliedType(tycon, addInto(args.head) :: Nil) - case tp @ AppliedType(tycon, args) if defn.isFunctionType(tp) => + case tp @ AppliedType(tycon, args) if defn.isFunctionNType(tp) => wrapConvertible(tp.derivedAppliedType(tycon, args.init :+ addInto(args.last))) case tp @ RefinedType(parent, rname, rinfo) if defn.isFunctionOrPolyType(tp) => wrapConvertible(tp.derivedRefinedType(parent, rname, addInto(rinfo))) diff --git a/compiler/src/dotty/tools/dotc/transform/BetaReduce.scala b/compiler/src/dotty/tools/dotc/transform/BetaReduce.scala index b8cbb4367db4..aafb64b33444 100644 --- a/compiler/src/dotty/tools/dotc/transform/BetaReduce.scala +++ b/compiler/src/dotty/tools/dotc/transform/BetaReduce.scala @@ -90,7 +90,7 @@ object BetaReduce: recur(expr, argss) case _ => None tree match - case Apply(Select(fn, nme.apply), args) if defn.isFunctionType(fn.tpe) => + case Apply(Select(fn, nme.apply), args) if defn.isFunctionNType(fn.tpe) => recur(fn, List(args)) match case Some(reduced) => seq(bindingsBuf.result(), reduced).withSpan(tree.span) diff --git a/compiler/src/dotty/tools/dotc/typer/Applications.scala b/compiler/src/dotty/tools/dotc/typer/Applications.scala index 4604ea2873e7..e5707106e325 100644 --- a/compiler/src/dotty/tools/dotc/typer/Applications.scala +++ b/compiler/src/dotty/tools/dotc/typer/Applications.scala @@ -695,7 +695,7 @@ trait Applications extends Compatibility { val argtpe1 = argtpe.widen def SAMargOK = - defn.isFunctionType(argtpe1) && formal.match + defn.isFunctionNType(argtpe1) && formal.match case SAMType(sam) => argtpe <:< sam.toFunctionType(isJava = formal.classSymbol.is(JavaDefined)) case _ => false diff --git a/compiler/src/dotty/tools/dotc/typer/Implicits.scala b/compiler/src/dotty/tools/dotc/typer/Implicits.scala index 5ae40421add2..d5dffff30afb 100644 --- a/compiler/src/dotty/tools/dotc/typer/Implicits.scala +++ b/compiler/src/dotty/tools/dotc/typer/Implicits.scala @@ -220,7 +220,7 @@ object Implicits: case pt: ViewProto => viewCandidateKind(ref.widen, pt.argType, pt.resType) case _: ValueTypeOrProto => - if (defn.isFunctionType(pt)) Candidate.Value + if (defn.isFunctionNType(pt)) Candidate.Value else valueTypeCandidateKind(ref.widen) case _ => Candidate.Value @@ -973,7 +973,7 @@ trait Implicits: /** A string indicating the formal parameter corresponding to a missing argument */ def implicitParamString(paramName: TermName, methodStr: String, tree: Tree)(using Context): String = tree match { - case Select(qual, nme.apply) if defn.isFunctionType(qual.tpe.widen) => + case Select(qual, nme.apply) if defn.isFunctionNType(qual.tpe.widen) => val qt = qual.tpe.widen val qt1 = qt.dealiasKeepAnnots def addendum = if (qt1 eq qt) "" else (i"\nWhere $qt is an alias of: $qt1") diff --git a/compiler/src/dotty/tools/dotc/typer/Synthesizer.scala b/compiler/src/dotty/tools/dotc/typer/Synthesizer.scala index 5bb6a25dbb56..e88546c0b71d 100644 --- a/compiler/src/dotty/tools/dotc/typer/Synthesizer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Synthesizer.scala @@ -106,7 +106,7 @@ class Synthesizer(typer: Typer)(using @constructorOnly c: Context): defn.isContextFunctionType(baseFun)) val arity: Int = if defn.isErasedFunctionType(fun) then -1 // TODO support? - else if defn.isFunctionType(fun) then + else if defn.isFunctionNType(fun) then // TupledFunction[(...) => R, ?] fun.functionArgInfos match case funArgs :+ funRet @@ -114,7 +114,7 @@ class Synthesizer(typer: Typer)(using @constructorOnly c: Context): // TupledFunction[(...funArgs...) => funRet, ?] funArgs.size case _ => -1 - else if defn.isFunctionType(tupled) then + else if defn.isFunctionNType(tupled) then // TupledFunction[?, (...) => R] tupled.functionArgInfos match case tupledArgs :: funRet :: Nil => diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala index ee8aa668296d..9d2826fbbd97 100644 --- a/compiler/src/dotty/tools/dotc/typer/Typer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala @@ -1685,7 +1685,7 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer case mt: MethodType => pt.findFunctionType match { case pt @ SAMType(sam) - if !defn.isFunctionType(pt) && mt <:< sam => + if !defn.isFunctionNType(pt) && mt <:< sam => // SAMs of the form C[?] where C is a class cannot be conversion targets. // The resulting class `class $anon extends C[?] {...}` would be illegal, // since type arguments to `C`'s super constructor cannot be constructed. @@ -2935,7 +2935,7 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer def typedAsFunction(tree: untpd.PostfixOp, pt: Type)(using Context): Tree = { val untpd.PostfixOp(qual, Ident(nme.WILDCARD)) = tree: @unchecked - val pt1 = if (defn.isFunctionType(pt)) pt else AnyFunctionProto + val pt1 = if (defn.isFunctionNType(pt)) pt else AnyFunctionProto val nestedCtx = ctx.fresh.setNewTyperState() val res = typed(qual, pt1)(using nestedCtx) res match { @@ -3957,7 +3957,7 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer sym.isConstructor || sym.matchNullaryLoosely || Feature.warnOnMigration(msg, tree.srcPos, version = `3.0`) - && { + && { msg.actions .headOption .foreach(Rewrites.applyAction) @@ -3990,7 +3990,7 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer // Ignore `.apply` in `m.apply(...)`; it will later be simplified in typedSelect to `m(...)` adapt1(tree, pt1, locked) else - if (!defn.isFunctionType(pt)) + if (!defn.isFunctionNType(pt)) pt match { case SAMType(_) if !pt.classSymbol.hasAnnotation(defn.FunctionalInterfaceAnnot) => report.warning(em"${tree.symbol} is eta-expanded even though $pt does not have the @FunctionalInterface annotation.", tree.srcPos) @@ -4108,7 +4108,7 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer def adaptNoArgs(wtp: Type): Tree = { val ptNorm = underlyingApplied(pt) - def functionExpected = defn.isFunctionType(ptNorm) + def functionExpected = defn.isFunctionNType(ptNorm) def needsEta = pt.revealIgnored match case _: SingletonType | _: FunOrPolyProto => false case _ => true @@ -4198,7 +4198,7 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer // convert function literal to SAM closure tree match { case closure(Nil, id @ Ident(nme.ANON_FUN), _) - if defn.isFunctionType(wtp) && !defn.isFunctionType(pt) => + if defn.isFunctionNType(wtp) && !defn.isFunctionNType(pt) => pt match { case SAMType(sam) if wtp <:< sam.toFunctionType(isJava = pt.classSymbol.is(JavaDefined)) => diff --git a/compiler/src/dotty/tools/dotc/util/Signatures.scala b/compiler/src/dotty/tools/dotc/util/Signatures.scala index 5513a1f803c6..877e02adfd7d 100644 --- a/compiler/src/dotty/tools/dotc/util/Signatures.scala +++ b/compiler/src/dotty/tools/dotc/util/Signatures.scala @@ -302,7 +302,7 @@ object Signatures { * @param tree tree to validate */ private def isValid(tree: tpd.Tree)(using Context): Boolean = - ctx.definitions.isTupleNType(tree.tpe) || ctx.definitions.isFunctionType(tree.tpe) + ctx.definitions.isTupleNType(tree.tpe) || ctx.definitions.isFunctionNType(tree.tpe) /** * Get unapply method result type omiting unknown types and another method calls. diff --git a/compiler/src/scala/quoted/runtime/impl/QuotesImpl.scala b/compiler/src/scala/quoted/runtime/impl/QuotesImpl.scala index 0388411e4bfb..7df98d57b5ff 100644 --- a/compiler/src/scala/quoted/runtime/impl/QuotesImpl.scala +++ b/compiler/src/scala/quoted/runtime/impl/QuotesImpl.scala @@ -1784,7 +1784,7 @@ class QuotesImpl private (using val ctx: Context) extends Quotes, QuoteUnpickler def baseType(cls: Symbol): TypeRepr = self.baseType(cls) def derivesFrom(cls: Symbol): Boolean = self.derivesFrom(cls) def isFunctionType: Boolean = - dotc.core.Symbols.defn.isFunctionType(self) + dotc.core.Symbols.defn.isFunctionNType(self) def isContextFunctionType: Boolean = dotc.core.Symbols.defn.isContextFunctionType(self) def isErasedFunctionType: Boolean = From d7167b05d76c8c62071b1ec51d17bbf6ae772e42 Mon Sep 17 00:00:00 2001 From: Nicolas Stucki Date: Wed, 12 Jul 2023 10:01:11 +0200 Subject: [PATCH 02/10] Rename `isFunctionOrPoly` to `isFunctionType` This method checks if the type is any kind of function type: `FunctionN`, `ContextFunctionN`, `PolyFunction`, and `ErasedFunction`. --- compiler/src/dotty/tools/dotc/cc/CheckCaptures.scala | 8 ++++---- compiler/src/dotty/tools/dotc/cc/Setup.scala | 6 +++--- compiler/src/dotty/tools/dotc/core/Definitions.scala | 2 +- compiler/src/dotty/tools/dotc/core/Types.scala | 2 +- .../src/dotty/tools/dotc/printing/RefinedPrinter.scala | 4 ++-- 5 files changed, 11 insertions(+), 11 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/cc/CheckCaptures.scala b/compiler/src/dotty/tools/dotc/cc/CheckCaptures.scala index e21da446ce76..039a9623ff5f 100644 --- a/compiler/src/dotty/tools/dotc/cc/CheckCaptures.scala +++ b/compiler/src/dotty/tools/dotc/cc/CheckCaptures.scala @@ -187,7 +187,7 @@ class CheckCaptures extends Recheck, SymTransformer: capt.println(i"solving $t") refs.solve() traverse(parent) - case t @ RefinedType(_, nme.apply, rinfo) if defn.isFunctionOrPolyType(t) => + case t @ RefinedType(_, nme.apply, rinfo) if defn.isFunctionType(t) => traverse(rinfo) case tp: TypeVar => case tp: TypeRef => @@ -769,7 +769,7 @@ class CheckCaptures extends Recheck, SymTransformer: case actual @ AppliedType(tycon, args) if defn.isNonRefinedFunction(actual) => adaptFun(actual, args.init, args.last, expected, covariant, insertBox, (aargs1, ares1) => actual.derivedAppliedType(tycon, aargs1 :+ ares1)) - case actual @ RefinedType(_, _, rinfo: MethodType) if defn.isFunctionOrPolyType(actual) => + case actual @ RefinedType(_, _, rinfo: MethodType) if defn.isFunctionType(actual) => // TODO Find a way to combine handling of generic and dependent function types (here and elsewhere) adaptFun(actual, rinfo.paramInfos, rinfo.resType, expected, covariant, insertBox, (aargs1, ares1) => @@ -779,7 +779,7 @@ class CheckCaptures extends Recheck, SymTransformer: adaptFun(actual, actual.paramInfos, actual.resType, expected, covariant, insertBox, (aargs1, ares1) => actual.derivedLambdaType(paramInfos = aargs1, resType = ares1)) - case actual @ RefinedType(p, nme, rinfo: PolyType) if defn.isFunctionOrPolyType(actual) => + case actual @ RefinedType(p, nme, rinfo: PolyType) if defn.isFunctionType(actual) => adaptTypeFun(actual, rinfo.resType, expected, covariant, insertBox, ares1 => val rinfo1 = rinfo.derivedLambdaType(rinfo.paramNames, rinfo.paramInfos, ares1) @@ -996,7 +996,7 @@ class CheckCaptures extends Recheck, SymTransformer: case CapturingType(parent, refs) => healCaptureSet(refs) traverse(parent) - case tp @ RefinedType(parent, rname, rinfo: MethodType) if defn.isFunctionOrPolyType(tp) => + case tp @ RefinedType(parent, rname, rinfo: MethodType) if defn.isFunctionType(tp) => traverse(rinfo) case tp: TermLambda => val saved = allowed diff --git a/compiler/src/dotty/tools/dotc/cc/Setup.scala b/compiler/src/dotty/tools/dotc/cc/Setup.scala index bbe54f14b86c..94219da31bdf 100644 --- a/compiler/src/dotty/tools/dotc/cc/Setup.scala +++ b/compiler/src/dotty/tools/dotc/cc/Setup.scala @@ -54,7 +54,7 @@ extends tpd.TreeTraverser: val boxedRes = recur(res) if boxedRes eq res then tp else tp1.derivedAppliedType(tycon, args.init :+ boxedRes) - case tp1 @ RefinedType(_, _, rinfo: MethodType) if defn.isFunctionOrPolyType(tp1) => + case tp1 @ RefinedType(_, _, rinfo: MethodType) if defn.isFunctionType(tp1) => val boxedRinfo = recur(rinfo) if boxedRinfo eq rinfo then tp else boxedRinfo.toFunctionType(isJava = false, alwaysDependent = true) @@ -231,7 +231,7 @@ extends tpd.TreeTraverser: tp.derivedAppliedType(tycon1, args1 :+ res1) else tp.derivedAppliedType(tycon1, args.mapConserve(arg => this(arg))) - case tp @ RefinedType(core, rname, rinfo: MethodType) if defn.isFunctionOrPolyType(tp) => + case tp @ RefinedType(core, rname, rinfo: MethodType) if defn.isFunctionType(tp) => val rinfo1 = apply(rinfo) if rinfo1 ne rinfo then rinfo1.toFunctionType(isJava = false, alwaysDependent = true) else tp @@ -329,7 +329,7 @@ extends tpd.TreeTraverser: args.last, CaptureSet.empty, currentCs ++ outerCs) tp.derivedAppliedType(tycon1, args1 :+ resType1) tp1.capturing(outerCs) - case tp @ RefinedType(parent, nme.apply, rinfo: MethodType) if defn.isFunctionOrPolyType(tp) => + case tp @ RefinedType(parent, nme.apply, rinfo: MethodType) if defn.isFunctionType(tp) => propagateDepFunctionResult(mapOver(tp), currentCs ++ outerCs) .capturing(outerCs) case _ => diff --git a/compiler/src/dotty/tools/dotc/core/Definitions.scala b/compiler/src/dotty/tools/dotc/core/Definitions.scala index f517cd2c2b13..3ec7fdf1cd38 100644 --- a/compiler/src/dotty/tools/dotc/core/Definitions.scala +++ b/compiler/src/dotty/tools/dotc/core/Definitions.scala @@ -1726,7 +1726,7 @@ class Definitions { * - ErasedFunction * - PolyFunction */ - def isFunctionOrPolyType(tp: Type)(using Context): Boolean = + def isFunctionType(tp: Type)(using Context): Boolean = isFunctionNType(tp) || isRefinedFunctionType(tp) private def withSpecMethods(cls: ClassSymbol, bases: List[Name], paramTypes: Set[TypeRef]) = diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index cfc1a2c35acb..0faae1aa8b5b 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -4073,7 +4073,7 @@ object Types { tp.derivedAppliedType(tycon, addInto(args.head) :: Nil) case tp @ AppliedType(tycon, args) if defn.isFunctionNType(tp) => wrapConvertible(tp.derivedAppliedType(tycon, args.init :+ addInto(args.last))) - case tp @ RefinedType(parent, rname, rinfo) if defn.isFunctionOrPolyType(tp) => + case tp @ RefinedType(parent, rname, rinfo) if defn.isFunctionType(tp) => wrapConvertible(tp.derivedRefinedType(parent, rname, addInto(rinfo))) case tp: MethodOrPoly => tp.derivedLambdaType(resType = addInto(tp.resType)) diff --git a/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala b/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala index 38de92a9cba5..b2fce4c793dc 100644 --- a/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala +++ b/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala @@ -266,7 +266,7 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) { if !printDebug && appliedText(tp.asInstanceOf[HKLambda].resType).isEmpty => // don't eta contract if the application would be printed specially toText(tycon) - case tp: RefinedType if defn.isFunctionOrPolyType(tp) && !printDebug => + case tp: RefinedType if defn.isFunctionType(tp) && !printDebug => toTextMethodAsFunction(tp.refinedInfo, isPure = Feature.pureFunsEnabled && !tp.typeSymbol.name.isImpureFunction) case tp: TypeRef => @@ -771,7 +771,7 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) { override protected def toTextCapturing(tp: Type, refsText: Text, boxText: Text): Text = tp match case tp: AppliedType if defn.isFunctionSymbol(tp.typeSymbol) && !printDebug => boxText ~ toTextFunction(tp, refsText) - case tp: RefinedType if defn.isFunctionOrPolyType(tp) && !printDebug => + case tp: RefinedType if defn.isFunctionType(tp) && !printDebug => boxText ~ toTextMethodAsFunction(tp.refinedInfo, isPure = !tp.typeSymbol.name.isImpureFunction, refsText) case _ => super.toTextCapturing(tp, refsText, boxText) From 63fa75a9f0b102b2c736706374761e6fa371fa84 Mon Sep 17 00:00:00 2001 From: Nicolas Stucki Date: Wed, 12 Jul 2023 10:37:11 +0200 Subject: [PATCH 03/10] More consistent use of `is{Refined,Poly,Erased}isFunctionType` --- compiler/src/dotty/tools/dotc/core/Definitions.scala | 8 ++++++-- compiler/src/dotty/tools/dotc/core/TypeApplications.scala | 3 +-- compiler/src/dotty/tools/dotc/core/TypeErasure.scala | 8 +++----- compiler/src/dotty/tools/dotc/transform/TreeChecker.scala | 8 +++----- 4 files changed, 13 insertions(+), 14 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/Definitions.scala b/compiler/src/dotty/tools/dotc/core/Definitions.scala index 3ec7fdf1cd38..b667205eca89 100644 --- a/compiler/src/dotty/tools/dotc/core/Definitions.scala +++ b/compiler/src/dotty/tools/dotc/core/Definitions.scala @@ -1714,9 +1714,13 @@ class Definitions { /** Is `tp` a specialized, refined function type? Either an `ErasedFunction` or a `PolyFunction`. */ def isRefinedFunctionType(tp: Type)(using Context): Boolean = - tp.derivesFrom(defn.PolyFunctionClass) || isErasedFunctionType(tp) + isPolyFunctionType(tp) || isErasedFunctionType(tp) - /** Is `tp` a specialized, refined function type? Either an `ErasedFunction`. */ + /** Is `tp` a specialized, refined `PolyFunction` type? */ + def isPolyFunctionType(tp: Type)(using Context): Boolean = + tp.derivesFrom(defn.PolyFunctionClass) + + /** Is `tp` a specialized, refined `ErasedFunction` type? */ def isErasedFunctionType(tp: Type)(using Context): Boolean = tp.derivesFrom(defn.ErasedFunctionClass) diff --git a/compiler/src/dotty/tools/dotc/core/TypeApplications.scala b/compiler/src/dotty/tools/dotc/core/TypeApplications.scala index 2e8aee4df96c..ce7d1d67d05c 100644 --- a/compiler/src/dotty/tools/dotc/core/TypeApplications.scala +++ b/compiler/src/dotty/tools/dotc/core/TypeApplications.scala @@ -509,8 +509,7 @@ class TypeApplications(val self: Type) extends AnyVal { * Handles `ErasedFunction`s and poly functions gracefully. */ final def functionArgInfos(using Context): List[Type] = self.dealias match - case RefinedType(parent, nme.apply, mt: MethodType) if defn.isErasedFunctionType(parent) => (mt.paramInfos :+ mt.resultType) - case RefinedType(parent, nme.apply, mt: MethodType) if parent.typeSymbol eq defn.PolyFunctionClass => (mt.paramInfos :+ mt.resultType) + case RefinedType(parent, nme.apply, mt: MethodType) if defn.isRefinedFunctionType(parent) => (mt.paramInfos :+ mt.resultType) case _ => self.dropDependentRefinement.dealias.argInfos /** Argument types where existential types in arguments are disallowed */ diff --git a/compiler/src/dotty/tools/dotc/core/TypeErasure.scala b/compiler/src/dotty/tools/dotc/core/TypeErasure.scala index 8d84c53bd144..9528f91385d2 100644 --- a/compiler/src/dotty/tools/dotc/core/TypeErasure.scala +++ b/compiler/src/dotty/tools/dotc/core/TypeErasure.scala @@ -592,7 +592,7 @@ import TypeErasure._ */ class TypeErasure(sourceLanguage: SourceLanguage, semiEraseVCs: Boolean, isConstructor: Boolean, isSymbol: Boolean, inSigName: Boolean) { - /** The erasure |T| of a type T. + /** The erasure |T| of a type T. * * If computing the erasure of T requires erasing a WildcardType or an * uninstantiated type variable, then an exception signaling an internal @@ -659,7 +659,7 @@ class TypeErasure(sourceLanguage: SourceLanguage, semiEraseVCs: Boolean, isConst else SuperType(eThis, eSuper) case ExprType(rt) => defn.FunctionType(0) - case RefinedType(parent, nme.apply, refinedInfo) if parent.typeSymbol eq defn.PolyFunctionClass => + case RefinedType(parent, nme.apply, refinedInfo) if defn.isPolyFunctionType(parent) => erasePolyFunctionApply(refinedInfo) case RefinedType(parent, nme.apply, refinedInfo: MethodType) if defn.isErasedFunctionType(parent) => eraseErasedFunctionApply(refinedInfo) @@ -943,13 +943,11 @@ class TypeErasure(sourceLanguage: SourceLanguage, semiEraseVCs: Boolean, isConst sigName(defn.FunctionOf(Nil, rt)) case tp: TypeVar if !tp.isInstantiated => tpnme.Uninstantiated - case tp @ RefinedType(parent, nme.apply, _) if parent.typeSymbol eq defn.PolyFunctionClass => + case tp @ RefinedType(parent, nme.apply, _) if defn.isRefinedFunctionType(parent) => // we need this case rather than falling through to the default // because RefinedTypes <: TypeProxy and it would be caught by // the case immediately below sigName(this(tp)) - case tp @ RefinedType(parent, nme.apply, refinedInfo) if defn.isErasedFunctionType(parent) => - sigName(this(tp)) case tp: TypeProxy => sigName(tp.underlying) case tp: WildcardType => diff --git a/compiler/src/dotty/tools/dotc/transform/TreeChecker.scala b/compiler/src/dotty/tools/dotc/transform/TreeChecker.scala index de611db6c14e..7cfcccf13f98 100644 --- a/compiler/src/dotty/tools/dotc/transform/TreeChecker.scala +++ b/compiler/src/dotty/tools/dotc/transform/TreeChecker.scala @@ -446,14 +446,12 @@ object TreeChecker { assert(tree.isTerm || !ctx.isAfterTyper, tree.show + " at " + ctx.phase) val tpe = tree.typeOpt - // Polymorphic apply methods stay structural until Erasure - val isPolyFunctionApply = (tree.name eq nme.apply) && tree.qualifier.typeOpt.derivesFrom(defn.PolyFunctionClass) - // Erased functions stay structural until Erasure - val isErasedFunctionApply = (tree.name eq nme.apply) && tree.qualifier.typeOpt.derivesFrom(defn.ErasedFunctionClass) + // PolyFunction and ErasedFunction apply methods stay structural until Erasure + val isRefinedFunctionApply = (tree.name eq nme.apply) && defn.isRefinedFunctionType(tree.qualifier.typeOpt) // Outer selects are pickled specially so don't require a symbol val isOuterSelect = tree.name.is(OuterSelectName) val isPrimitiveArrayOp = ctx.erasedTypes && nme.isPrimitiveName(tree.name) - if !(tree.isType || isPolyFunctionApply || isErasedFunctionApply || isOuterSelect || isPrimitiveArrayOp) then + if !(tree.isType || isRefinedFunctionApply || isOuterSelect || isPrimitiveArrayOp) then val denot = tree.denot assert(denot.exists, i"Selection $tree with type $tpe does not have a denotation") assert(denot.symbol.exists, i"Denotation $denot of selection $tree with type $tpe does not have a symbol, qualifier type = ${tree.qualifier.typeOpt}") From a420d71ef7e8f58ede8519f60dddd902a02852ad Mon Sep 17 00:00:00 2001 From: Nicolas Stucki Date: Wed, 12 Jul 2023 10:54:03 +0200 Subject: [PATCH 04/10] Generalize/simplify refined function type Erasure The erasure now supports polymorphic function types with erased parameters. We still need to add support for this in the typer. --- .../dotty/tools/dotc/core/TypeErasure.scala | 34 ++++++++----------- .../dotty/tools/dotc/transform/Erasure.scala | 6 ++-- 2 files changed, 17 insertions(+), 23 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/TypeErasure.scala b/compiler/src/dotty/tools/dotc/core/TypeErasure.scala index 9528f91385d2..c376916cce05 100644 --- a/compiler/src/dotty/tools/dotc/core/TypeErasure.scala +++ b/compiler/src/dotty/tools/dotc/core/TypeErasure.scala @@ -560,21 +560,19 @@ object TypeErasure { case _ => false } - /** The erasure of `PolyFunction { def apply: $applyInfo }` */ - def erasePolyFunctionApply(applyInfo: Type)(using Context): Type = - assert(applyInfo.isInstanceOf[PolyType]) - val res = applyInfo.resultType - val paramss = res.paramNamess - assert(paramss.length == 1) - erasure(defn.FunctionType(paramss.head.length, - isContextual = res.isImplicitMethod)) - - def eraseErasedFunctionApply(erasedFn: MethodType)(using Context): Type = - val fnType = defn.FunctionType( - n = erasedFn.erasedParams.count(_ == false), - isContextual = erasedFn.isContextualMethod, - ) - erasure(fnType) + /** The erasure of `(PolyFunction | ErasedFunction) { def apply: $applyInfo }` */ + def eraseRefinedFunctionApply(applyInfo: Type)(using Context): Type = + def functionType(info: Type): Type = info match { + case info: PolyType => + functionType(info.resultType) + case info: MethodType => + assert(!info.resultType.isInstanceOf[MethodicType]) + defn.FunctionType( + n = info.erasedParams.count(_ == false), + isContextual = info.isImplicitMethod, + ) + } + erasure(functionType(applyInfo)) } import TypeErasure._ @@ -659,10 +657,8 @@ class TypeErasure(sourceLanguage: SourceLanguage, semiEraseVCs: Boolean, isConst else SuperType(eThis, eSuper) case ExprType(rt) => defn.FunctionType(0) - case RefinedType(parent, nme.apply, refinedInfo) if defn.isPolyFunctionType(parent) => - erasePolyFunctionApply(refinedInfo) - case RefinedType(parent, nme.apply, refinedInfo: MethodType) if defn.isErasedFunctionType(parent) => - eraseErasedFunctionApply(refinedInfo) + case RefinedType(parent, nme.apply, refinedInfo) if defn.isRefinedFunctionType(parent) => + eraseRefinedFunctionApply(refinedInfo) case tp: TypeVar if !tp.isInstantiated => assert(inSigName, i"Cannot erase uninstantiated type variable $tp") WildcardType diff --git a/compiler/src/dotty/tools/dotc/transform/Erasure.scala b/compiler/src/dotty/tools/dotc/transform/Erasure.scala index 8e355175c176..9993250d3d0a 100644 --- a/compiler/src/dotty/tools/dotc/transform/Erasure.scala +++ b/compiler/src/dotty/tools/dotc/transform/Erasure.scala @@ -679,10 +679,8 @@ object Erasure { // Instead, we manually lookup the type of `apply` in the qualifier. inContext(preErasureCtx) { val qualTp = tree.qualifier.typeOpt.widen - if qualTp.derivesFrom(defn.PolyFunctionClass) then - erasePolyFunctionApply(qualTp.select(nme.apply).widen).classSymbol - else if defn.isErasedFunctionType(qualTp) then - eraseErasedFunctionApply(qualTp.select(nme.apply).widen.asInstanceOf[MethodType]).classSymbol + if defn.isRefinedFunctionType(qualTp) then + eraseRefinedFunctionApply(qualTp.select(nme.apply).widen).classSymbol else NoSymbol } From 8a202e55a1da8d10ea05a7c46c52c1c787e5f1f4 Mon Sep 17 00:00:00 2001 From: Nicolas Stucki Date: Wed, 12 Jul 2023 11:29:58 +0200 Subject: [PATCH 05/10] Remove use of `isFunctionNType` --- .../dotty/tools/dotc/core/TypeComparer.scala | 22 ++++++++++--------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/TypeComparer.scala b/compiler/src/dotty/tools/dotc/core/TypeComparer.scala index 2aa3e56f60d8..f2b2a1661ebd 100644 --- a/compiler/src/dotty/tools/dotc/core/TypeComparer.scala +++ b/compiler/src/dotty/tools/dotc/core/TypeComparer.scala @@ -665,16 +665,18 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling case _ => isSubType(info1, info2) - if defn.isFunctionNType(tp2) then - tp1w.widenDealias match - case tp1: RefinedType => - return isSubInfo(tp1.refinedInfo, tp2.refinedInfo) - case _ => - else if tp2.parent.typeSymbol == defn.PolyFunctionClass then - tp1.member(nme.apply).info match - case info1: PolyType => - return isSubInfo(info1, tp2.refinedInfo) - case _ => + if defn.isFunctionType(tp2) then + if defn.isPolyFunctionType(tp2) then + // TODO should we handle ErasedFunction is this same way? + tp1.member(nme.apply).info match + case info1: PolyType => + return isSubInfo(info1, tp2.refinedInfo) + case _ => + else + tp1w.widenDealias match + case tp1: RefinedType => + return isSubInfo(tp1.refinedInfo, tp2.refinedInfo) + case _ => val skipped2 = skipMatching(tp1w, tp2) if (skipped2 eq tp2) || !Config.fastPathForRefinedSubtype then From 81f5677b9132ccbf84ad892984e4e97df04c871c Mon Sep 17 00:00:00 2001 From: Nicolas Stucki Date: Wed, 12 Jul 2023 16:59:44 +0200 Subject: [PATCH 06/10] Fix toFunctionType to handle erased function types --- compiler/src/dotty/tools/dotc/core/Definitions.scala | 1 + compiler/src/dotty/tools/dotc/core/Types.scala | 5 ++++- tests/run-custom-args/erased/quotes-reflection.check | 8 ++++---- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/Definitions.scala b/compiler/src/dotty/tools/dotc/core/Definitions.scala index b667205eca89..792fee9c6d3c 100644 --- a/compiler/src/dotty/tools/dotc/core/Definitions.scala +++ b/compiler/src/dotty/tools/dotc/core/Definitions.scala @@ -1475,6 +1475,7 @@ class Definitions { def PolyFunctionType = PolyFunctionClass.typeRef lazy val ErasedFunctionClass = requiredClass("scala.runtime.ErasedFunction") + def ErasedFunctionType = ErasedFunctionClass.typeRef /** If `cls` is a class in the scala package, its name, otherwise EmptyTypeName */ def scalaClassName(cls: Symbol)(using Context): TypeName = cls.denot match diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index 0faae1aa8b5b..7ad5199efede 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -1875,7 +1875,7 @@ object Types { * @param alwaysDependent if true, always create a dependent function type. */ def toFunctionType(isJava: Boolean, dropLast: Int = 0, alwaysDependent: Boolean = false)(using Context): Type = this match { - case mt: MethodType if !mt.isParamDependent => + case mt: MethodType if !mt.isParamDependent && !mt.hasErasedParams => val formals1 = if (dropLast == 0) mt.paramInfos else mt.paramInfos dropRight dropLast val isContextual = mt.isContextualMethod && !ctx.erasedTypes val result1 = mt.nonDependentResultApprox match { @@ -1888,6 +1888,9 @@ object Types { if alwaysDependent || mt.isResultDependent then RefinedType(funType, nme.apply, mt) else funType + case mt: MethodType if !mt.isParamDependent => + assert(mt.hasErasedParams) + RefinedType(defn.ErasedFunctionType, nme.apply, mt) case poly @ PolyType(_, mt: MethodType) if !mt.isParamDependent => RefinedType(defn.PolyFunctionType, nme.apply, poly) } diff --git a/tests/run-custom-args/erased/quotes-reflection.check b/tests/run-custom-args/erased/quotes-reflection.check index 838479e0b7af..584714624b45 100644 --- a/tests/run-custom-args/erased/quotes-reflection.check +++ b/tests/run-custom-args/erased/quotes-reflection.check @@ -4,7 +4,7 @@ method m2: (i: scala.Int) isGiven=false isImplicit=false erasedArgs=List(true) method m3: (i: scala.Int, j: scala.Int) isGiven=false isImplicit=false erasedArgs=List(false, true) method m4: (i: EC) isGiven=false isImplicit=false erasedArgs=List(true) val l1: scala.ContextFunction1[scala.Int, scala.Int] -val l2: scala.runtime.ErasedFunction with apply: (x$0: scala.Int @scala.annotation.internal.ErasedParam) isImplicit=false erasedParams=List(true) -val l3: scala.runtime.ErasedFunction with apply: (x$0: scala.Int @scala.annotation.internal.ErasedParam) isImplicit=true erasedParams=List(true) -val l4: scala.runtime.ErasedFunction with apply: (x$0: scala.Int, x$1: scala.Int @scala.annotation.internal.ErasedParam) isImplicit=false erasedParams=List(false, true) -val l5: scala.runtime.ErasedFunction with apply: (x$0: EC @scala.annotation.internal.ErasedParam) isImplicit=false erasedParams=List(true) +val l2: scala.runtime.ErasedFunction with apply: (x: scala.Int @scala.annotation.internal.ErasedParam) isImplicit=false erasedParams=List(true) +val l3: scala.runtime.ErasedFunction with apply: (x: scala.Int @scala.annotation.internal.ErasedParam) isImplicit=true erasedParams=List(true) +val l4: scala.runtime.ErasedFunction with apply: (x: scala.Int, y: scala.Int @scala.annotation.internal.ErasedParam) isImplicit=false erasedParams=List(false, true) +val l5: scala.runtime.ErasedFunction with apply: (x: EC @scala.annotation.internal.ErasedParam) isImplicit=false erasedParams=List(true) From 3ea39eaddf378806f192d91a69f8bf2ee793e2c1 Mon Sep 17 00:00:00 2001 From: Nicolas Stucki Date: Thu, 13 Jul 2023 16:20:13 +0200 Subject: [PATCH 07/10] Simplify function erasure --- compiler/src/dotty/tools/dotc/core/TypeErasure.scala | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/TypeErasure.scala b/compiler/src/dotty/tools/dotc/core/TypeErasure.scala index c376916cce05..9806457e86b1 100644 --- a/compiler/src/dotty/tools/dotc/core/TypeErasure.scala +++ b/compiler/src/dotty/tools/dotc/core/TypeErasure.scala @@ -567,10 +567,7 @@ object TypeErasure { functionType(info.resultType) case info: MethodType => assert(!info.resultType.isInstanceOf[MethodicType]) - defn.FunctionType( - n = info.erasedParams.count(_ == false), - isContextual = info.isImplicitMethod, - ) + defn.FunctionType(n = info.erasedParams.count(_ == false)) } erasure(functionType(applyInfo)) } From aca69bd1c997c9be7ac3c9ea83f04982443542cb Mon Sep 17 00:00:00 2001 From: Nicolas Stucki Date: Thu, 13 Jul 2023 16:22:09 +0200 Subject: [PATCH 08/10] Refactor toFunctionType --- .../src/dotty/tools/dotc/core/Types.scala | 36 ++++++++++--------- 1 file changed, 19 insertions(+), 17 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index 7ad5199efede..59506e3f1419 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -1875,23 +1875,25 @@ object Types { * @param alwaysDependent if true, always create a dependent function type. */ def toFunctionType(isJava: Boolean, dropLast: Int = 0, alwaysDependent: Boolean = false)(using Context): Type = this match { - case mt: MethodType if !mt.isParamDependent && !mt.hasErasedParams => - val formals1 = if (dropLast == 0) mt.paramInfos else mt.paramInfos dropRight dropLast - val isContextual = mt.isContextualMethod && !ctx.erasedTypes - val result1 = mt.nonDependentResultApprox match { - case res: MethodType => res.toFunctionType(isJava) - case res => res - } - val funType = defn.FunctionOf( - formals1 mapConserve (_.translateFromRepeated(toArray = isJava)), - result1, isContextual) - if alwaysDependent || mt.isResultDependent then - RefinedType(funType, nme.apply, mt) - else funType - case mt: MethodType if !mt.isParamDependent => - assert(mt.hasErasedParams) - RefinedType(defn.ErasedFunctionType, nme.apply, mt) - case poly @ PolyType(_, mt: MethodType) if !mt.isParamDependent => + case mt: MethodType => + assert(!mt.isParamDependent) + def nonDependentFunType = + val formals1 = if (dropLast == 0) mt.paramInfos else mt.paramInfos dropRight dropLast + val isContextual = mt.isContextualMethod && !ctx.erasedTypes + val result1 = mt.nonDependentResultApprox match { + case res: MethodType => res.toFunctionType(isJava) + case res => res + } + defn.FunctionOf( + formals1 mapConserve (_.translateFromRepeated(toArray = isJava)), + result1, isContextual) + if mt.hasErasedParams then + RefinedType(defn.ErasedFunctionType, nme.apply, mt) + else if alwaysDependent || mt.isResultDependent then + RefinedType(nonDependentFunType, nme.apply, mt) + else nonDependentFunType + case poly @ PolyType(_, mt: MethodType) => + assert(!mt.isParamDependent) RefinedType(defn.PolyFunctionType, nme.apply, poly) } From 96af36370ad166a2f06c4fcf6dad7d53aa433d73 Mon Sep 17 00:00:00 2001 From: Nicolas Stucki Date: Thu, 13 Jul 2023 16:25:59 +0200 Subject: [PATCH 09/10] Rename isRefinedFunctionType to isPolyOrErasedFunctionType --- compiler/src/dotty/tools/dotc/ast/TreeInfo.scala | 2 +- compiler/src/dotty/tools/dotc/core/Definitions.scala | 4 ++-- compiler/src/dotty/tools/dotc/core/TypeApplications.scala | 2 +- compiler/src/dotty/tools/dotc/core/TypeErasure.scala | 4 ++-- compiler/src/dotty/tools/dotc/transform/Erasure.scala | 2 +- compiler/src/dotty/tools/dotc/transform/TreeChecker.scala | 2 +- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/ast/TreeInfo.scala b/compiler/src/dotty/tools/dotc/ast/TreeInfo.scala index 9f6aa3a3db70..a6c0646d7163 100644 --- a/compiler/src/dotty/tools/dotc/ast/TreeInfo.scala +++ b/compiler/src/dotty/tools/dotc/ast/TreeInfo.scala @@ -968,7 +968,7 @@ trait TypedTreeInfo extends TreeInfo[Type] { self: Trees.Instance[Type] => && tree.isTerm && { val qualType = tree.qualifier.tpe - hasRefinement(qualType) && !defn.isRefinedFunctionType(qualType) + hasRefinement(qualType) && !defn.isPolyOrErasedFunctionType(qualType) } def loop(tree: Tree): Boolean = tree match case TypeApply(fun, _) => diff --git a/compiler/src/dotty/tools/dotc/core/Definitions.scala b/compiler/src/dotty/tools/dotc/core/Definitions.scala index 792fee9c6d3c..45ab42fd5cbe 100644 --- a/compiler/src/dotty/tools/dotc/core/Definitions.scala +++ b/compiler/src/dotty/tools/dotc/core/Definitions.scala @@ -1714,7 +1714,7 @@ class Definitions { isNonRefinedFunction(tp.dropDependentRefinement) /** Is `tp` a specialized, refined function type? Either an `ErasedFunction` or a `PolyFunction`. */ - def isRefinedFunctionType(tp: Type)(using Context): Boolean = + def isPolyOrErasedFunctionType(tp: Type)(using Context): Boolean = isPolyFunctionType(tp) || isErasedFunctionType(tp) /** Is `tp` a specialized, refined `PolyFunction` type? */ @@ -1732,7 +1732,7 @@ class Definitions { * - PolyFunction */ def isFunctionType(tp: Type)(using Context): Boolean = - isFunctionNType(tp) || isRefinedFunctionType(tp) + isFunctionNType(tp) || isPolyOrErasedFunctionType(tp) private def withSpecMethods(cls: ClassSymbol, bases: List[Name], paramTypes: Set[TypeRef]) = if !ctx.settings.Yscala2Stdlib.value then diff --git a/compiler/src/dotty/tools/dotc/core/TypeApplications.scala b/compiler/src/dotty/tools/dotc/core/TypeApplications.scala index ce7d1d67d05c..667869947c6e 100644 --- a/compiler/src/dotty/tools/dotc/core/TypeApplications.scala +++ b/compiler/src/dotty/tools/dotc/core/TypeApplications.scala @@ -509,7 +509,7 @@ class TypeApplications(val self: Type) extends AnyVal { * Handles `ErasedFunction`s and poly functions gracefully. */ final def functionArgInfos(using Context): List[Type] = self.dealias match - case RefinedType(parent, nme.apply, mt: MethodType) if defn.isRefinedFunctionType(parent) => (mt.paramInfos :+ mt.resultType) + case RefinedType(parent, nme.apply, mt: MethodType) if defn.isPolyOrErasedFunctionType(parent) => (mt.paramInfos :+ mt.resultType) case _ => self.dropDependentRefinement.dealias.argInfos /** Argument types where existential types in arguments are disallowed */ diff --git a/compiler/src/dotty/tools/dotc/core/TypeErasure.scala b/compiler/src/dotty/tools/dotc/core/TypeErasure.scala index 9806457e86b1..b29f88aaa010 100644 --- a/compiler/src/dotty/tools/dotc/core/TypeErasure.scala +++ b/compiler/src/dotty/tools/dotc/core/TypeErasure.scala @@ -654,7 +654,7 @@ class TypeErasure(sourceLanguage: SourceLanguage, semiEraseVCs: Boolean, isConst else SuperType(eThis, eSuper) case ExprType(rt) => defn.FunctionType(0) - case RefinedType(parent, nme.apply, refinedInfo) if defn.isRefinedFunctionType(parent) => + case RefinedType(parent, nme.apply, refinedInfo) if defn.isPolyOrErasedFunctionType(parent) => eraseRefinedFunctionApply(refinedInfo) case tp: TypeVar if !tp.isInstantiated => assert(inSigName, i"Cannot erase uninstantiated type variable $tp") @@ -936,7 +936,7 @@ class TypeErasure(sourceLanguage: SourceLanguage, semiEraseVCs: Boolean, isConst sigName(defn.FunctionOf(Nil, rt)) case tp: TypeVar if !tp.isInstantiated => tpnme.Uninstantiated - case tp @ RefinedType(parent, nme.apply, _) if defn.isRefinedFunctionType(parent) => + case tp @ RefinedType(parent, nme.apply, _) if defn.isPolyOrErasedFunctionType(parent) => // we need this case rather than falling through to the default // because RefinedTypes <: TypeProxy and it would be caught by // the case immediately below diff --git a/compiler/src/dotty/tools/dotc/transform/Erasure.scala b/compiler/src/dotty/tools/dotc/transform/Erasure.scala index 9993250d3d0a..3ed024429bb6 100644 --- a/compiler/src/dotty/tools/dotc/transform/Erasure.scala +++ b/compiler/src/dotty/tools/dotc/transform/Erasure.scala @@ -679,7 +679,7 @@ object Erasure { // Instead, we manually lookup the type of `apply` in the qualifier. inContext(preErasureCtx) { val qualTp = tree.qualifier.typeOpt.widen - if defn.isRefinedFunctionType(qualTp) then + if defn.isPolyOrErasedFunctionType(qualTp) then eraseRefinedFunctionApply(qualTp.select(nme.apply).widen).classSymbol else NoSymbol diff --git a/compiler/src/dotty/tools/dotc/transform/TreeChecker.scala b/compiler/src/dotty/tools/dotc/transform/TreeChecker.scala index 7cfcccf13f98..b08c23db557a 100644 --- a/compiler/src/dotty/tools/dotc/transform/TreeChecker.scala +++ b/compiler/src/dotty/tools/dotc/transform/TreeChecker.scala @@ -447,7 +447,7 @@ object TreeChecker { val tpe = tree.typeOpt // PolyFunction and ErasedFunction apply methods stay structural until Erasure - val isRefinedFunctionApply = (tree.name eq nme.apply) && defn.isRefinedFunctionType(tree.qualifier.typeOpt) + val isRefinedFunctionApply = (tree.name eq nme.apply) && defn.isPolyOrErasedFunctionType(tree.qualifier.typeOpt) // Outer selects are pickled specially so don't require a symbol val isOuterSelect = tree.name.is(OuterSelectName) val isPrimitiveArrayOp = ctx.erasedTypes && nme.isPrimitiveName(tree.name) From 21818e7325ff331ccf6f040541d0afb7bdf91b71 Mon Sep 17 00:00:00 2001 From: Nicolas Stucki Date: Thu, 13 Jul 2023 16:49:28 +0200 Subject: [PATCH 10/10] Fix documentation --- compiler/src/dotty/tools/dotc/core/Definitions.scala | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/Definitions.scala b/compiler/src/dotty/tools/dotc/core/Definitions.scala index 45ab42fd5cbe..e2afe906a9c4 100644 --- a/compiler/src/dotty/tools/dotc/core/Definitions.scala +++ b/compiler/src/dotty/tools/dotc/core/Definitions.scala @@ -1713,15 +1713,15 @@ class Definitions { def isFunctionNType(tp: Type)(using Context): Boolean = isNonRefinedFunction(tp.dropDependentRefinement) - /** Is `tp` a specialized, refined function type? Either an `ErasedFunction` or a `PolyFunction`. */ + /** Does `tp` derive from `PolyFunction` or `ErasedFunction`? */ def isPolyOrErasedFunctionType(tp: Type)(using Context): Boolean = isPolyFunctionType(tp) || isErasedFunctionType(tp) - /** Is `tp` a specialized, refined `PolyFunction` type? */ + /** Does `tp` derive from `PolyFunction`? */ def isPolyFunctionType(tp: Type)(using Context): Boolean = tp.derivesFrom(defn.PolyFunctionClass) - /** Is `tp` a specialized, refined `ErasedFunction` type? */ + /** Does `tp` derive from `ErasedFunction`? */ def isErasedFunctionType(tp: Type)(using Context): Boolean = tp.derivesFrom(defn.ErasedFunctionClass)