Skip to content

Commit d61d7f9

Browse files
authored
Merge pull request scala#7207 from dotty-staging/fix-6190
Fix scala#6190: eta-expand companion object if functions are expected
2 parents eab8783 + 63eb4bf commit d61d7f9

File tree

25 files changed

+74
-72
lines changed

25 files changed

+74
-72
lines changed

community-build/src/scala/dotty/communitybuild/projects.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,7 @@ final case class SbtCommunityProject(
150150
)
151151

152152
private val baseCommand =
153-
"clean; set logLevel in Global := Level.Error; set updateOptions in Global ~= (_.withLatestSnapshots(false)); "
153+
"clean; set updateOptions in Global ~= (_.withLatestSnapshots(false)); "
154154
++ s"""set dependencyOverrides in ThisBuild ++= ${dependencyOverrides.mkString("Seq(", ", ", ")")}; """
155155
++ s"++$compilerVersion!; "
156156

compiler/src/dotty/tools/backend/sjs/JSExportsGen.scala

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -330,12 +330,12 @@ final class JSExportsGen(jsCodeGen: JSCodeGen)(using Context) {
330330
if (isProp)
331331
genExportProperty(alts, jsName, static)
332332
else
333-
genExportMethod(alts.map(Exported), jsName, static)
333+
genExportMethod(alts.map(Exported.apply), jsName, static)
334334
}
335335
}
336336

337337
def genJSConstructorDispatch(alts: List[Symbol]): (Option[List[js.ParamDef]], js.JSMethodDef) = {
338-
val exporteds = alts.map(Exported)
338+
val exporteds = alts.map(Exported.apply)
339339

340340
val isConstructorOfNestedJSClass = exporteds.head.isConstructorOfNestedJSClass
341341
assert(exporteds.tail.forall(_.isConstructorOfNestedJSClass == isConstructorOfNestedJSClass),
@@ -391,7 +391,7 @@ final class JSExportsGen(jsCodeGen: JSCodeGen)(using Context) {
391391
} else {
392392
val formalArgsRegistry = new FormalArgsRegistry(1, false)
393393
val List(arg) = formalArgsRegistry.genFormalArgs()
394-
val body = genExportSameArgc(jsName, formalArgsRegistry, setters.map(Exported), static, None)
394+
val body = genExportSameArgc(jsName, formalArgsRegistry, setters.map(Exported.apply), static, None)
395395
Some((arg, body))
396396
}
397397
}

compiler/src/dotty/tools/dotc/ast/Desugar.scala

Lines changed: 1 addition & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -676,28 +676,6 @@ object desugar {
676676
mods.is(Private) || (!mods.is(Protected) && mods.hasPrivateWithin)
677677
}
678678

679-
/** Does one of the parameter's types (in the first param clause)
680-
* mention a preceding parameter?
681-
*/
682-
def isParamDependent = constrVparamss match
683-
case vparams :: _ =>
684-
val paramNames = vparams.map(_.name).toSet
685-
vparams.exists(_.tpt.existsSubTree {
686-
case Ident(name: TermName) => paramNames.contains(name)
687-
case _ => false
688-
})
689-
case _ => false
690-
691-
val companionParent =
692-
if constrTparams.nonEmpty
693-
|| constrVparamss.length > 1
694-
|| mods.is(Abstract)
695-
|| restrictedAccess
696-
|| isParamDependent
697-
|| isEnumCase
698-
then anyRef
699-
else
700-
constrVparamss.foldRight(classTypeRef)((vparams, restpe) => Function(vparams map (_.tpt), restpe))
701679
val applyMeths =
702680
if (mods.is(Abstract)) Nil
703681
else {
@@ -727,7 +705,7 @@ object desugar {
727705
val toStringMeth =
728706
DefDef(nme.toString_, Nil, Nil, TypeTree(), Literal(Constant(className.toString))).withMods(Modifiers(Override | Synthetic))
729707

730-
companionDefs(companionParent, applyMeths ::: unapplyMeth :: toStringMeth :: companionMembers)
708+
companionDefs(anyRef, applyMeths ::: unapplyMeth :: toStringMeth :: companionMembers)
731709
}
732710
else if (companionMembers.nonEmpty || companionDerived.nonEmpty || isEnum)
733711
companionDefs(anyRef, companionMembers)

compiler/src/dotty/tools/dotc/ast/TreeInfo.scala

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -585,14 +585,6 @@ trait TypedTreeInfo extends TreeInfo[Type] { self: Trees.Instance[Type] =>
585585
case _ => false
586586
}
587587

588-
/** Is tree a compiler-generated `.apply` node that refers to the
589-
* apply of a function class?
590-
*/
591-
def isSyntheticApply(tree: Tree): Boolean = tree match {
592-
case Select(qual, nme.apply) => tree.span.end == qual.span.end
593-
case _ => false
594-
}
595-
596588
/** Strips layers of `.asInstanceOf[T]` / `_.$asInstanceOf[T]()` from an expression */
597589
def stripCast(tree: Tree)(using Context): Tree = {
598590
def isCast(sel: Tree) = sel.symbol.isTypeCast

compiler/src/dotty/tools/dotc/classpath/DirectoryClassPath.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -195,7 +195,7 @@ final class JrtClassPath(fs: java.nio.file.FileSystem) extends ClassPath with No
195195
}
196196

197197
case class DirectoryClassPath(dir: JFile) extends JFileDirectoryLookup[ClassFileEntryImpl] with NoSourcePaths {
198-
override def findClass(className: String): Option[ClassRepresentation] = findClassFile(className) map ClassFileEntryImpl
198+
override def findClass(className: String): Option[ClassRepresentation] = findClassFile(className) map ClassFileEntryImpl.apply
199199

200200
def findClassFile(className: String): Option[AbstractFile] = {
201201
val relativePath = FileUtils.dirPath(className)
@@ -220,7 +220,7 @@ case class DirectorySourcePath(dir: JFile) extends JFileDirectoryLookup[SourceFi
220220
protected def createFileEntry(file: AbstractFile): SourceFileEntryImpl = SourceFileEntryImpl(file)
221221
protected def isMatchingFile(f: JFile): Boolean = endsScalaOrJava(f.getName)
222222

223-
override def findClass(className: String): Option[ClassRepresentation] = findSourceFile(className) map SourceFileEntryImpl
223+
override def findClass(className: String): Option[ClassRepresentation] = findSourceFile(className) map SourceFileEntryImpl.apply
224224

225225
private def findSourceFile(className: String): Option[AbstractFile] = {
226226
val relativePath = FileUtils.dirPath(className)

compiler/src/dotty/tools/dotc/classpath/VirtualDirectoryClassPath.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ case class VirtualDirectoryClassPath(dir: VirtualDirectory) extends ClassPath wi
3838
def asURLs: Seq[URL] = Seq(new URL(dir.name))
3939
def asClassPathStrings: Seq[String] = Seq(dir.path)
4040

41-
override def findClass(className: String): Option[ClassRepresentation] = findClassFile(className) map ClassFileEntryImpl
41+
override def findClass(className: String): Option[ClassRepresentation] = findClassFile(className) map ClassFileEntryImpl.apply
4242

4343
def findClassFile(className: String): Option[AbstractFile] = {
4444
val relativePath = FileUtils.dirPath(className) + ".class"

compiler/src/dotty/tools/dotc/parsing/Parsers.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -77,8 +77,8 @@ object Parsers {
7777
if source.isSelfContained then new ScriptParser(source)
7878
else new Parser(source)
7979

80-
private val InCase: Region => Region = Scanners.InCase
81-
private val InCond: Region => Region = Scanners.InBraces
80+
private val InCase: Region => Region = Scanners.InCase.apply
81+
private val InCond: Region => Region = Scanners.InBraces.apply
8282

8383
abstract class ParserCommon(val source: SourceFile)(using Context) {
8484

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

Lines changed: 24 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,14 @@ object Typer {
8484
*/
8585
private[typer] val HiddenSearchFailure = new Property.Key[List[SearchFailure]]
8686

87+
/** Is tree a compiler-generated `.apply` node that refers to the
88+
* apply of a function class?
89+
*/
90+
private[typer] def isSyntheticApply(tree: tpd.Tree): Boolean = tree match {
91+
case tree: tpd.Select => tree.hasAttachment(InsertedApply)
92+
case _ => false
93+
}
94+
8795
/** Add `fail` to the list of search failures attached to `tree` */
8896
def rememberSearchFailure(tree: tpd.Tree, fail: SearchFailure) =
8997
tree.putAttachment(HiddenSearchFailure,
@@ -2843,11 +2851,6 @@ class Typer extends Namer
28432851
case _ => false
28442852
}
28452853

2846-
def isSyntheticApply(tree: Tree): Boolean = tree match {
2847-
case tree: Select => tree.hasAttachment(InsertedApply)
2848-
case _ => false
2849-
}
2850-
28512854
def tryApply(using Context) = {
28522855
val pt1 = pt.withContext(ctx)
28532856
val sel = typedSelect(untpd.Select(untpd.TypedSplice(tree), nme.apply), pt1)
@@ -3222,9 +3225,6 @@ class Typer extends Namer
32223225
* Examples for these cases are found in run/implicitFuns.scala and neg/i2006.scala.
32233226
*/
32243227
def adaptNoArgsUnappliedMethod(wtp: MethodType, functionExpected: Boolean, arity: Int): Tree = {
3225-
def isExpandableApply =
3226-
defn.isContextFunctionClass(tree.symbol.maybeOwner) && functionExpected
3227-
32283228
/** Is reference to this symbol `f` automatically expanded to `f()`? */
32293229
def isAutoApplied(sym: Symbol): Boolean =
32303230
sym.isConstructor
@@ -3241,7 +3241,7 @@ class Typer extends Namer
32413241
!tree.symbol.isConstructor &&
32423242
!tree.symbol.isAllOf(InlineMethod) &&
32433243
!ctx.mode.is(Mode.Pattern) &&
3244-
!(isSyntheticApply(tree) && !isExpandableApply)) {
3244+
!(isSyntheticApply(tree) && !functionExpected)) {
32453245
if (!defn.isFunctionType(pt))
32463246
pt match {
32473247
case SAMType(_) if !pt.classSymbol.hasAnnotation(defn.FunctionalInterfaceAnnot) =>
@@ -3266,16 +3266,26 @@ class Typer extends Namer
32663266
defn.isContextFunctionClass(underlying.classSymbol)
32673267
}
32683268

3269-
def adaptNoArgsOther(wtp: Type): Tree = {
3270-
if (isContextFunctionRef(wtp) &&
3271-
!untpd.isContextualClosure(tree) &&
3269+
def adaptNoArgsOther(wtp: Type, functionExpected: Boolean): Tree = {
3270+
val implicitFun = isContextFunctionRef(wtp) && !untpd.isContextualClosure(tree)
3271+
def caseCompanion =
3272+
functionExpected &&
3273+
tree.symbol.is(Module) &&
3274+
tree.symbol.companionClass.is(Case) &&
3275+
!tree.tpe.baseClasses.exists(defn.isFunctionClass) && {
3276+
report.warning("The method `apply` is inserted. The auto insertion will be deprecated, please write `" + tree.show + ".apply` explicitly.", tree.sourcePos)
3277+
true
3278+
}
3279+
3280+
if ((implicitFun || caseCompanion) &&
32723281
!isApplyProto(pt) &&
32733282
pt != AssignProto &&
32743283
!ctx.mode.is(Mode.Pattern) &&
32753284
!ctx.isAfterTyper &&
32763285
!ctx.isInlineContext) {
32773286
typr.println(i"insert apply on implicit $tree")
3278-
typed(untpd.Select(untpd.TypedSplice(tree), nme.apply), pt, locked)
3287+
val sel = untpd.Select(untpd.TypedSplice(tree), nme.apply).withAttachment(InsertedApply, ())
3288+
try typed(sel, pt, locked) finally sel.removeAttachment(InsertedApply)
32793289
}
32803290
else if (ctx.mode is Mode.Pattern) {
32813291
checkEqualityEvidence(tree, pt)
@@ -3388,7 +3398,7 @@ class Typer extends Namer
33883398
}
33893399
adaptNoArgsUnappliedMethod(wtp, funExpected, arity)
33903400
case _ =>
3391-
adaptNoArgsOther(wtp)
3401+
adaptNoArgsOther(wtp, functionExpected)
33923402
}
33933403
}
33943404

doc-tool/src/dotty/tools/dottydoc/core/DocASTPhase.scala

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -114,11 +114,11 @@ class DocASTPhase extends Phase {
114114
case c @ TypeDef(n, rhs) if c.symbol.isClass =>
115115
//TODO: should not `collectMember` from `rhs` - instead: get from symbol, will get inherited members as well
116116
val parameters = (c.symbol, annotations(c.symbol), n.show, collectMembers(rhs), flags(c), path(c.symbol), typeParams(c.symbol), constructors(c.symbol), superTypes(c), None, Nil, None)
117-
if (c.symbol.is(Flags.CaseClass)) {
118-
CaseClassImpl.tupled(parameters) :: Nil
119-
} else {
120-
ClassImpl.tupled(parameters) :: Nil
121-
}
117+
val constr =
118+
if (c.symbol.is(Flags.CaseClass)) CaseClassImpl.apply
119+
else ClassImpl.apply
120+
121+
constr.tupled(parameters) :: Nil
122122

123123
/** def */
124124
case d: DefDef =>

doc-tool/src/dotty/tools/dottydoc/util/MemberLookup.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ trait MemberLookup {
8181
): EntityLink = {
8282
val link =
8383
lookup(Some(entity), packages, query)
84-
.map(LinkToEntity)
84+
.map(LinkToEntity.apply)
8585
.getOrElse(Tooltip(query))
8686

8787
EntityLink(title, link)

scala3doc/src/dotty/dokka/tasty/ScalaDocSupport.scala

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -79,10 +79,10 @@ trait ScaladocSupport { self: TastyParser =>
7979
addOpt(parsed.version)(dkkd.Version(_))
8080
addOpt(parsed.since)(dkkd.Since(_))
8181
addOpt(parsed.deprecated)(dkkd.Deprecated(_))
82-
addSeq(parsed.todo)(ScalaTagWrapper.Todo)
83-
addSeq(parsed.see)(ScalaTagWrapper.See)
84-
addSeq(parsed.note)(ScalaTagWrapper.Note)
85-
addSeq(parsed.example)(ScalaTagWrapper.Example)
82+
addSeq(parsed.todo)(ScalaTagWrapper.Todo.apply)
83+
addSeq(parsed.see)(ScalaTagWrapper.See.apply)
84+
addSeq(parsed.note)(ScalaTagWrapper.Note.apply)
85+
addSeq(parsed.example)(ScalaTagWrapper.Example.apply)
8686

8787
addOpt(parsed.constructor)(dkkd.Constructor(_))
8888
addSeq(parsed.valueParams){ case (name, tag) =>

tests/neg-custom-args/fatal-warnings/i6190a.check

Whitespace-only changes.
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
-- Error: tests/neg-custom-args/fatal-warnings/i6190b.scala:3:29 -------------------------------------------------------
2+
3 |def foo = List("1", "2").map(Rule) // error
3+
| ^^^^
4+
| The method `apply` is inserted. The auto insertion will be deprecated, please write `Rule.apply` explicitly.
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
case class Rule(name: String)
2+
3+
def foo = List("1", "2").map(Rule) // error

tests/neg/enums.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ enum E4 {
2222
case C4(x: Int)
2323
}
2424
object E4 {
25-
val x1: Int => E4 = C4 // error: found: C4, required: Int => E4
25+
val x1: Int => E4 = C4 // ok
2626
val x2: Int => E4 = C4(_) // ok
2727
}
2828

tests/neg/i6190.scala

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
class Rule(name: String)
2+
object Rule {
3+
def apply(name: String): Rule = new Rule(name)
4+
}
5+
6+
def foo = List("1", "2").map(Rule) // error

tests/pos/t3137.scala renamed to tests/neg/t3137.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,5 +13,5 @@ trait AA {
1313
}
1414

1515
class BB extends AA {
16-
case class C(v: Int)
16+
case class C(v: Int) // error
1717
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
case class Rule(name: String)
2+
object Rule extends (String => Rule) {
3+
def apply(name: String): Rule = new Rule(name)
4+
}
5+
6+
def foo = List("1", "2").map(Rule)
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
case class Rule(name: String)
2+
3+
def foo = List("1", "2").map(Rule.apply)

tests/run-macros/tasty-extractors-2.check

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ TypeRef(ThisType(TypeRef(NoPrefix(), "scala")), "Unit")
4949
Inlined(None, Nil, Block(List(ClassDef("Foo", DefDef("<init>", Nil, List(Nil), Inferred(), None), List(Apply(Select(New(Inferred()), "<init>"), Nil)), Nil, None, List(DefDef("a", Nil, Nil, Inferred(), Some(Literal(Constant.Int(0))))))), Literal(Constant.Unit())))
5050
TypeRef(ThisType(TypeRef(NoPrefix(), "scala")), "Unit")
5151

52-
Inlined(None, Nil, Block(List(ClassDef("Foo", DefDef("<init>", Nil, List(Nil), Inferred(), None), List(Apply(Select(New(Inferred()), "<init>"), Nil), TypeSelect(Select(Ident("_root_"), "scala"), "Product"), TypeSelect(Select(Ident("_root_"), "scala"), "Serializable")), Nil, None, List(DefDef("copy", Nil, List(Nil), Inferred(), Some(Apply(Select(New(Inferred()), "<init>"), Nil))))), ValDef("Foo", TypeIdent("Foo$"), Some(Apply(Select(New(TypeIdent("Foo$")), "<init>"), Nil))), ClassDef("Foo$", DefDef("<init>", Nil, List(Nil), Inferred(), None), List(Apply(Select(New(Inferred()), "<init>"), Nil), Applied(Inferred(), List(Inferred()))), Nil, Some(ValDef("_", Singleton(Ident("Foo")), None)), List(DefDef("apply", Nil, List(Nil), Inferred(), Some(Apply(Select(New(Inferred()), "<init>"), Nil))), DefDef("unapply", Nil, List(List(ValDef("x$1", Inferred(), None))), Singleton(Literal(Constant.Boolean(true))), Some(Literal(Constant.Boolean(true)))), DefDef("toString", Nil, Nil, Inferred(), Some(Literal(Constant.String("Foo"))))))), Literal(Constant.Unit())))
52+
Inlined(None, Nil, Block(List(ClassDef("Foo", DefDef("<init>", Nil, List(Nil), Inferred(), None), List(Apply(Select(New(Inferred()), "<init>"), Nil), TypeSelect(Select(Ident("_root_"), "scala"), "Product"), TypeSelect(Select(Ident("_root_"), "scala"), "Serializable")), Nil, None, List(DefDef("copy", Nil, List(Nil), Inferred(), Some(Apply(Select(New(Inferred()), "<init>"), Nil))))), ValDef("Foo", TypeIdent("Foo$"), Some(Apply(Select(New(TypeIdent("Foo$")), "<init>"), Nil))), ClassDef("Foo$", DefDef("<init>", Nil, List(Nil), Inferred(), None), List(Apply(Select(New(Inferred()), "<init>"), Nil)), Nil, Some(ValDef("_", Singleton(Ident("Foo")), None)), List(DefDef("apply", Nil, List(Nil), Inferred(), Some(Apply(Select(New(Inferred()), "<init>"), Nil))), DefDef("unapply", Nil, List(List(ValDef("x$1", Inferred(), None))), Singleton(Literal(Constant.Boolean(true))), Some(Literal(Constant.Boolean(true)))), DefDef("toString", Nil, Nil, Inferred(), Some(Literal(Constant.String("Foo"))))))), Literal(Constant.Unit())))
5353
TypeRef(ThisType(TypeRef(NoPrefix(), "scala")), "Unit")
5454

5555
Inlined(None, Nil, Block(List(ClassDef("Foo1", DefDef("<init>", Nil, List(List(ValDef("a", TypeIdent("Int"), None))), Inferred(), None), List(Apply(Select(New(Inferred()), "<init>"), Nil)), Nil, None, List(ValDef("a", Inferred(), None)))), Literal(Constant.Unit())))

0 commit comments

Comments
 (0)