Thanks to visit codestin.com
Credit goes to github.com

Skip to content
Draft
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
9 changes: 5 additions & 4 deletions src/compiler/scala/tools/nsc/ast/TreeGen.scala
Original file line number Diff line number Diff line change
Expand Up @@ -309,8 +309,9 @@ abstract class TreeGen extends scala.reflect.internal.TreeGen with TreeDSL {
resTp: Type = functionResultType(fun.tpe),
additionalFlags: FlagSet = NoFlags): DefDef = {
val methSym = owner.newMethod(name, fun.pos, FINAL | additionalFlags)
// for sams, methParamProtos is the parameter symbols for the sam's method, so that we generate the correct override (based on parameter types)
val methParamSyms = methParamProtos.map { param => methSym.newSyntheticValueParam(param.tpe, param.name.toTermName) }
// for sams, methParamProtos is the parameter symbols for the sam's method,
// so that we generate the correct override (based on parameter types)
val methParamSyms = methParamProtos.map(param => methSym.newSyntheticValueParam(param.tpe, param.name.toTermName))
methSym setInfo MethodType(methParamSyms, resTp)

// we must rewire reference to the function's param symbols -- and not methParamProtos -- to methParamSyms
Expand All @@ -326,8 +327,8 @@ abstract class TreeGen extends scala.reflect.internal.TreeGen with TreeDSL {
val enclosingStaticModules = owner.ownersIterator.filter(x => !x.hasPackageFlag && x.isModuleClass && x.isStatic)
enclosingStaticModules.foldLeft(tree)((tree, moduleClass) => tree.substituteThis(moduleClass, gen.mkAttributedIdent(moduleClass.sourceModule)) )
}

newDefDef(methSym, substThisForModule(moveToMethod(useMethodParams(fun.body))))(tpt = TypeTree(resTp))
val body = substThisForModule(moveToMethod(useMethodParams(fun.body)))
newDefDef(methSym, body)(tpt = TypeTree(resTp))
}

/**
Expand Down
178 changes: 105 additions & 73 deletions src/compiler/scala/tools/nsc/transform/UnCurry.scala

Large diffs are not rendered by default.

68 changes: 34 additions & 34 deletions src/compiler/scala/tools/nsc/typechecker/Typers.scala
Original file line number Diff line number Diff line change
Expand Up @@ -3045,10 +3045,10 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
if (samTp eq NoType) false
else {
/* Make a synthetic class symbol to represent the synthetic class that
* will be spun up by LMF for this function. This is necessary because
* it's possible that the SAM method might need bridges, and they have
* to go somewhere. Erasure knows to compute bridges for these classes
* just as if they were real templates extending the SAM type. */
* will be spun up by LMF for this function. This is necessary because
* it's possible that the SAM method might need bridges, and they have
* to go somewhere. Erasure knows to compute bridges for these classes
* just as if they were real templates extending the SAM type. */
val synthCls = fun.symbol.owner.newClassWithInfo(
name = tpnme.ANON_CLASS_NAME,
parents = ObjectTpe :: samTp :: Nil,
Expand All @@ -3065,8 +3065,8 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
fun.setType(samTp)

/* Arguably I should do `fun.setSymbol(samCls)` rather than leaning
* on an attachment, but doing that confounds lambdalift's free var
* analysis in a way which does not seem to be trivially reparable. */
* on an attachment, but doing that confounds lambdalift's free var
* analysis in a way which does not seem to be trivially reparable. */
fun.updateAttachment(SAMFunction(samTp, sam, synthCls))

true
Expand Down Expand Up @@ -5038,44 +5038,44 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
* the function of type `() => $T$`, which evaluates $e$ when it is applied to the empty parameter list `()`.
*/
def typedEta(methodValue: Tree): Tree = methodValue.tpe match {
case tp@(MethodType(_, _) | PolyType(_, MethodType(_, _))) => // (1)
case tp @ (MethodType(_, _) | PolyType(_, MethodType(_, _))) => // (1)
if (tp.params.lengthCompare(definitions.MaxFunctionArity) > 0) MaxFunctionArityError(methodValue, s"; method ${methodValue.symbol.name} cannot be eta-expanded because it takes ${tp.params.length} arguments")
else {
val etaPt =
pt match {
case pt: ProtoType =>
pt.asFunctionType orElse functionType(WildcardType.fillList(tp.params.length), WildcardType) orElse WildcardType // arity overflow --> NoType
case _ => pt
}

// We know syntactically methodValue can't refer to a constructor because you can't write `this _` for that (right???)
val etaPt = pt match {
case pt: ProtoType =>
pt.asFunctionType
.orElse(functionType(WildcardType.fillList(tp.params.length), WildcardType))
.orElse(WildcardType) // arity overflow --> NoType
case pt => pt
}
// We know syntactically methodValue can't refer to a constructor because you can't write `this _`
typedEtaExpansion(methodValue, mode, etaPt)
}

case TypeRef(_, ByNameParamClass, _) | NullaryMethodType(_) => // (2)
def warnNullary(tree: Tree) = {
val msg = "Methods without a parameter list and by-name params " +
"can no longer be converted to functions as `m _`, " +
"write a function literal `() => m` instead"
val pos = tree.pos
val action = {
val etaPos = pos.withEnd(pos.end + 2)
if (pos.source.sourceAt(etaPos).endsWith(" _"))
runReporting.codeAction("replace by function literal", etaPos, s"() => ${pos.source.sourceAt(pos)}", msg)
else Nil
}
if (currentRun.isScala3)
context.warning(pos, msg, Scala3Migration, action)
else
context.deprecationWarning(pos, NoSymbol, msg, "2.13.2", action)
}
val pos = methodValue.pos
// must create it here to change owner (normally done by typed's typedFunction)
// must create it here to change owner (normally done by typer's typedFunction)
val funSym = context.owner.newAnonymousFunctionValue(pos)
new ChangeOwnerTraverser(context.owner, funSym) traverse methodValue

val result = typed(Function(Nil, methodValue) setSymbol funSym setPos pos, mode, pt)

val msg = "Methods without a parameter list and by-name params can no longer be converted to functions as `m _`, " +
"write a function literal `() => m` instead"

val action = {
val etaPos = pos.withEnd(pos.end + 2)
if (pos.source.sourceAt(etaPos).endsWith(" _"))
runReporting.codeAction("replace by function literal", etaPos, s"() => ${pos.source.sourceAt(pos)}", msg)
else Nil
}

if (currentRun.isScala3)
context.warning(pos, msg, Scala3Migration, action)
else
context.deprecationWarning(pos, NoSymbol, msg, "2.13.2", action)

result
typed(Function(Nil, methodValue).setSymbol(funSym).setPos(pos), mode, pt)
.tap(warnNullary)

case ErrorType =>
methodValue
Expand Down
66 changes: 34 additions & 32 deletions src/compiler/scala/tools/tasty/TastyFormat.scala
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,14 @@ package scala.tools.tasty
// revision: https://github.com/scala/scala3/commit/24bff2a019afcf0f45ddfd3af6b213e7e228471c
object TastyFormat {

/** The first four bytes of a TASTy file, followed by four values:
* - `MajorVersion: Int` - see definition in `TastyFormat`
* - `MinorVersion: Int` - see definition in `TastyFormat`
* - `ExperimentalVersion: Int` - see definition in `TastyFormat`
* - `ToolingVersion: String` - arbitrary length string representing the tool that produced the TASTy.
*/
/** The TASTy file header.
*
* The first four bytes of a TASTy file, followed by four values:
* - `MajorVersion: Int` - see definition in `TastyFormat`
* - `MinorVersion: Int` - see definition in `TastyFormat`
* - `ExperimentalVersion: Int` - see definition in `TastyFormat`
* - `ToolingVersion: String` - arbitrary length string representing the tool that produced the TASTy.
*/
final val header: Array[Int] = Array(0x5C, 0xA1, 0xAB, 0x1F)

/** Natural number. Each increment of the `MajorVersion` begins a
Expand Down Expand Up @@ -54,39 +56,39 @@ object TastyFormat {
*/
final val ExperimentalVersion: Int = 0

/**This method implements a binary relation (`<:<`) between two TASTy versions.
/** This method implements a binary relation (`<:<`) between two TASTy versions.
*
* We label the lhs `file` and rhs `compiler`.
* if `file <:< compiler` then the TASTy file is valid to be read.
* We label the lhs `file` and rhs `compiler`.
* if `file <:< compiler` then the TASTy file is valid to be read.
*
* A TASTy version, e.g. `v := 28.0-3` is composed of three fields:
* - v.major == 28
* - v.minor == 0
* - v.experimental == 3
* A TASTy version, e.g. `v := 28.0-3` is composed of three fields:
* - v.major == 28
* - v.minor == 0
* - v.experimental == 3
*
* TASTy versions have a partial order, for example,
* `a <:< b` and `b <:< a` are both false if
* - `a` and `b` have different `major` fields.
* - `a` and `b` have the same `major` & `minor` fields,
* but different `experimental` fields, both non-zero.
* TASTy versions have a partial order, for example,
* `a <:< b` and `b <:< a` are both false if
* - `a` and `b` have different `major` fields.
* - `a` and `b` have the same `major` & `minor` fields,
* but different `experimental` fields, both non-zero.
*
* A TASTy version with a zero value for its `experimental` field
* is considered to be stable. Files with a stable TASTy version
* can be read by a compiler with an unstable TASTy version,
* (where the compiler's TASTy version has a higher `minor` field).
* A TASTy version with a zero value for its `experimental` field
* is considered to be stable. Files with a stable TASTy version
* can be read by a compiler with an unstable TASTy version,
* (where the compiler's TASTy version has a higher `minor` field).
*
* A compiler with a stable TASTy version can never read a file
* with an unstable TASTy version.
* A compiler with a stable TASTy version can never read a file
* with an unstable TASTy version.
*
* We follow the given algorithm:
* We follow the given algorithm:
*
* ```
* (fileMajor, fileMinor, fileExperimental) match
* case (`compilerMajor`, `compilerMinor`, `compilerExperimental`) => true // full equality
* case (`compilerMajor`, minor, 0) if minor < compilerMinor => true // stable backwards compatibility
* case _ => false
* ```
* @syntax markdown
* {{{
* (fileMajor, fileMinor, fileExperimental) match
* case (`compilerMajor`, `compilerMinor`, `compilerExperimental`) => true // full equality
* case (`compilerMajor`, minor, 0) if minor < compilerMinor => true // stable backwards compatibility
* case _ => false
* }}}
* @syntax markdown
*/
def isVersionCompatible(
fileMajor: Int,
Expand Down
26 changes: 14 additions & 12 deletions src/reflect/scala/reflect/internal/StdAttachments.scala
Original file line number Diff line number Diff line change
Expand Up @@ -50,21 +50,23 @@ trait StdAttachments {
}

/** Stores the trees that give rise to a refined type to be used in reification.
* Unfortunately typed `CompoundTypeTree` is lacking essential info, and the reifier cannot use `CompoundTypeTree.tpe`.
* Therefore we need this hack (see `Reshape.toPreTyperTypeTree` for a detailed explanation).
*
* Typed `CompoundTypeTree` is lacking info required by the reifier, which can't use `CompoundTypeTree.tpe`.
* (See `Reshape.toPreTyperTypeTree` for a detailed explanation.)
*/
case class CompoundTypeTreeOriginalAttachment(parents: List[Tree], stats: List[Tree])

/** Attached to a Function node during type checking when the expected type is a SAM type (and not a built-in FunctionN).
*
* Ideally, we'd move to Dotty's Closure AST, which tracks the environment,
* the lifted method that has the implementation, and the target type.
* For backwards compatibility, an attachment is the best we can do right now.
*
* @param samTp the expected type that triggered sam conversion (may be a subtype of the type corresponding to sam's owner)
* @param sam the single abstract method implemented by the Function we're attaching this to
* @param synthCls the (synthetic) class representing the eventual implementation class (spun at runtime by LMF on the JVM)
*/
/** A Function node was type checked with an expected type that is a SAM type and not a built-in FunctionN.
*
* Dotty's Closure AST improves on this because it tracks the environment,
* the lifted method that has the implementation, and the target type.
*
* @param samTp the expected type that triggered sam conversion
* (may be a subtype of the type corresponding to sam's owner)
* @param sam the single abstract method implemented by the Function we're attaching this to
* @param synthCls the (synthetic) class representing the eventual implementation class
* (spun at runtime by LMF on the JVM)
*/
case class SAMFunction(samTp: Type, sam: Symbol, synthCls: Symbol) extends PlainAttachment

case object DelambdafyTarget extends PlainAttachment
Expand Down
4 changes: 2 additions & 2 deletions src/reflect/scala/reflect/internal/transform/Transforms.scala
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ import scala.language.existentials
trait Transforms { self: SymbolTable =>

/** We need to encode laziness by hand here because the three components refChecks, uncurry and erasure
* are overwritten by objects in Global.
* It would be best of objects could override lazy values. See scala/bug#5187.
* are overridden by objects in Global.
* It would be best if objects could override lazy values. See scala/bug#5187.
* In the absence of this, the Lazy functionality should probably be somewhere
* in the standard library. Or is it already?
*/
Expand Down
8 changes: 3 additions & 5 deletions src/reflect/scala/reflect/internal/transform/UnCurry.scala
Original file line number Diff line number Diff line change
Expand Up @@ -47,9 +47,8 @@ trait UnCurry {

val uncurry: TypeMap = new TypeMap {
@tailrec
def apply(tp0: Type): Type = {
val tp = expandAlias(tp0)
tp match {
def apply(tp: Type): Type =
expandAlias(tp) match {
case MethodType(params, MethodType(params1, restpe)) =>
// This transformation is described in UnCurryTransformer.dependentParamTypeErasure
val packSymbolsMap = new TypeMap {
Expand All @@ -67,10 +66,9 @@ trait UnCurry {
apply(MethodType(List(), restpe))
case DesugaredParameterType(desugaredTpe) =>
apply(desugaredTpe)
case _ =>
case tp =>
expandAlias(tp.mapOver(this))
}
}
}

object DesugaredParameterType {
Expand Down
11 changes: 9 additions & 2 deletions src/reflect/scala/reflect/macros/Attachments.scala
Original file line number Diff line number Diff line change
Expand Up @@ -66,8 +66,15 @@ abstract class Attachments { self =>
}

/** Check underlying payload contains an instance of type `T`. */
def contains[T: ClassTag]: Boolean =
!isEmpty && (all exists matchesTag[T])
def contains[T: ClassTag]: Boolean = !isEmpty && {
val it = all.iterator
val matchesTagFn = matchesTag[T]
while (it.hasNext) { // OPT: hotspot, hand roll `Set.exists`.
val datum = it.next()
if (matchesTagFn(datum)) return true
}
false
}

/** Creates a copy of this attachment with the payload slot of T added/updated with the provided value.
* Replaces an existing payload of the same type, if exists.
Expand Down
5 changes: 4 additions & 1 deletion test/files/neg/varargs.check
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,7 @@ varargs.scala:20: error: A method annotated with @varargs must have a single rep
varargs.scala:23: error: A method annotated with @varargs must have a single repeated parameter in its last parameter list.
@varargs def v6: Int = 1 // nok
^
6 errors
varargs.scala:24: error: A method annotated with @varargs must have a single repeated parameter in its last parameter list.
@varargs def v7(i: Int*)() = i.sum // nok, was: (?)
^
7 errors
2 changes: 1 addition & 1 deletion test/files/neg/varargs.scala
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,6 @@ object Test {
@varargs def v5(a: String)(b: Int*) = a + b.sum // ok

@varargs def v6: Int = 1 // nok
@varargs def v7(i: Int*)() = i.sum // ok (?)
@varargs def v7(i: Int*)() = i.sum // nok, was: (?)

}
20 changes: 20 additions & 0 deletions test/files/run/t11237.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@

trait Semigroup[F] { self =>
def append(f1: F, f2: => F): F
val z = 10
}

case class Box(i: Int)

class R extends Runnable {
def run() = {
val boxSemigroup: Semigroup[Box] = (x1, x2) => Box(x1.i + x2.i)
// disallowed, by-name must be inferred
//val boxSemigroup: Semigroup[Box] = (x1: Box, x2: Box) => Box(Math.max(x1.i, x2.i))
assert(boxSemigroup.append(Box(1), Box(2)) == Box(3))
}
}

object Test extends App {
new R().run()
}