Skip to content

Change workings of experimental into modifier on parameter types #19673

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Feb 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 6 additions & 17 deletions compiler/src/dotty/tools/dotc/ast/Desugar.scala
Original file line number Diff line number Diff line change
Expand Up @@ -178,21 +178,7 @@ object desugar {
val valName = normalizeName(vdef, tpt).asTermName
var mods1 = vdef.mods

def dropInto(tpt: Tree): Tree = tpt match
case Into(tpt1) =>
mods1 = vdef.mods.withAddedAnnotation(
TypedSplice(
Annotation(defn.AllowConversionsAnnot, tpt.span.startPos).tree))
tpt1
case ByNameTypeTree(tpt1) =>
cpy.ByNameTypeTree(tpt)(dropInto(tpt1))
case PostfixOp(tpt1, op) if op.name == tpnme.raw.STAR =>
cpy.PostfixOp(tpt)(dropInto(tpt1), op)
case _ =>
tpt

val vdef1 = cpy.ValDef(vdef)(name = valName, tpt = dropInto(tpt))
.withMods(mods1)
val vdef1 = cpy.ValDef(vdef)(name = valName).withMods(mods1)

if isSetterNeeded(vdef) then
val setterParam = makeSyntheticParameter(tpt = SetterParamTree().watching(vdef))
Expand Down Expand Up @@ -1876,8 +1862,11 @@ object desugar {
assert(ctx.mode.isExpr || ctx.reporter.errorsReported || ctx.mode.is(Mode.Interactive), ctx.mode)
Select(t, op.name)
case PrefixOp(op, t) =>
val nspace = if (ctx.mode.is(Mode.Type)) tpnme else nme
Select(t, nspace.UNARY_PREFIX ++ op.name)
if op.name == tpnme.into then
Annotated(t, New(ref(defn.IntoAnnot.typeRef), Nil :: Nil))
else
val nspace = if (ctx.mode.is(Mode.Type)) tpnme else nme
Select(t, nspace.UNARY_PREFIX ++ op.name)
case ForDo(enums, body) =>
makeFor(nme.foreach, nme.foreach, enums, body) orElse tree
case ForYield(enums, body) =>
Expand Down
1 change: 1 addition & 0 deletions compiler/src/dotty/tools/dotc/ast/Trees.scala
Original file line number Diff line number Diff line change
Expand Up @@ -304,6 +304,7 @@ object Trees {

def withFlags(flags: FlagSet): ThisTree[Untyped] = withMods(untpd.Modifiers(flags))
def withAddedFlags(flags: FlagSet): ThisTree[Untyped] = withMods(rawMods | flags)
def withAddedAnnotation(annot: Tree[Untyped]): ThisTree[Untyped] = withMods(rawMods.withAddedAnnotation(annot))

/** Destructively update modifiers. To be used with care. */
def setMods(mods: untpd.Modifiers): Unit = myMods = mods
Expand Down
14 changes: 6 additions & 8 deletions compiler/src/dotty/tools/dotc/ast/untpd.scala
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,6 @@ object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo {
case class ContextBounds(bounds: TypeBoundsTree, cxBounds: List[Tree])(implicit @constructorOnly src: SourceFile) extends TypTree
case class PatDef(mods: Modifiers, pats: List[Tree], tpt: Tree, rhs: Tree)(implicit @constructorOnly src: SourceFile) extends DefTree
case class ExtMethods(paramss: List[ParamClause], methods: List[Tree])(implicit @constructorOnly src: SourceFile) extends Tree
case class Into(tpt: Tree)(implicit @constructorOnly src: SourceFile) extends Tree
case class MacroTree(expr: Tree)(implicit @constructorOnly src: SourceFile) extends Tree

case class ImportSelector(imported: Ident, renamed: Tree = EmptyTree, bound: Tree = EmptyTree)(implicit @constructorOnly src: SourceFile) extends Tree {
Expand Down Expand Up @@ -552,6 +551,12 @@ object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo {
ValDef(nme.syntheticParamName(n), if (tpt == null) TypeTree() else tpt, EmptyTree)
.withFlags(flags)

def isInto(t: Tree)(using Context): Boolean = t match
case PrefixOp(Ident(tpnme.into), _) => true
case Function(_, res) => isInto(res)
case Parens(t) => isInto(t)
case _ => false

def lambdaAbstract(params: List[ValDef] | List[TypeDef], tpt: Tree)(using Context): Tree =
params match
case Nil => tpt
Expand Down Expand Up @@ -666,9 +671,6 @@ object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo {
def ExtMethods(tree: Tree)(paramss: List[ParamClause], methods: List[Tree])(using Context): Tree = tree match
case tree: ExtMethods if (paramss eq tree.paramss) && (methods == tree.methods) => tree
case _ => finalize(tree, untpd.ExtMethods(paramss, methods)(tree.source))
def Into(tree: Tree)(tpt: Tree)(using Context): Tree = tree match
case tree: Into if tpt eq tree.tpt => tree
case _ => finalize(tree, untpd.Into(tpt)(tree.source))
def ImportSelector(tree: Tree)(imported: Ident, renamed: Tree, bound: Tree)(using Context): Tree = tree match {
case tree: ImportSelector if (imported eq tree.imported) && (renamed eq tree.renamed) && (bound eq tree.bound) => tree
case _ => finalize(tree, untpd.ImportSelector(imported, renamed, bound)(tree.source))
Expand Down Expand Up @@ -734,8 +736,6 @@ object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo {
cpy.PatDef(tree)(mods, transform(pats), transform(tpt), transform(rhs))
case ExtMethods(paramss, methods) =>
cpy.ExtMethods(tree)(transformParamss(paramss), transformSub(methods))
case Into(tpt) =>
cpy.Into(tree)(transform(tpt))
case ImportSelector(imported, renamed, bound) =>
cpy.ImportSelector(tree)(transformSub(imported), transform(renamed), transform(bound))
case Number(_, _) | TypedSplice(_) =>
Expand Down Expand Up @@ -791,8 +791,6 @@ object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo {
this(this(this(x, pats), tpt), rhs)
case ExtMethods(paramss, methods) =>
this(paramss.foldLeft(x)(apply), methods)
case Into(tpt) =>
this(x, tpt)
case ImportSelector(imported, renamed, bound) =>
this(this(this(x, imported), renamed), bound)
case Number(_, _) =>
Expand Down
6 changes: 2 additions & 4 deletions compiler/src/dotty/tools/dotc/core/Definitions.scala
Original file line number Diff line number Diff line change
Expand Up @@ -642,8 +642,6 @@ class Definitions {

@tu lazy val RepeatedParamClass: ClassSymbol = enterSpecialPolyClass(tpnme.REPEATED_PARAM_CLASS, Covariant, Seq(ObjectType, SeqType))

@tu lazy val IntoType: TypeSymbol = enterAliasType(tpnme.INTO, HKTypeLambda(TypeBounds.empty :: Nil)(_.paramRefs(0)))

// fundamental classes
@tu lazy val StringClass: ClassSymbol = requiredClass("java.lang.String")
def StringType: Type = StringClass.typeRef
Expand Down Expand Up @@ -1002,7 +1000,6 @@ class Definitions {
@tu lazy val JavaAnnotationClass: ClassSymbol = requiredClass("java.lang.annotation.Annotation")

// Annotation classes
@tu lazy val AllowConversionsAnnot: ClassSymbol = requiredClass("scala.annotation.allowConversions")
@tu lazy val AnnotationDefaultAnnot: ClassSymbol = requiredClass("scala.annotation.internal.AnnotationDefault")
@tu lazy val AssignedNonLocallyAnnot: ClassSymbol = requiredClass("scala.annotation.internal.AssignedNonLocally")
@tu lazy val BeanPropertyAnnot: ClassSymbol = requiredClass("scala.beans.BeanProperty")
Expand All @@ -1018,6 +1015,8 @@ class Definitions {
@tu lazy val ImplicitAmbiguousAnnot: ClassSymbol = requiredClass("scala.annotation.implicitAmbiguous")
@tu lazy val ImplicitNotFoundAnnot: ClassSymbol = requiredClass("scala.annotation.implicitNotFound")
@tu lazy val InlineParamAnnot: ClassSymbol = requiredClass("scala.annotation.internal.InlineParam")
@tu lazy val IntoAnnot: ClassSymbol = requiredClass("scala.annotation.into")
@tu lazy val IntoParamAnnot: ClassSymbol = requiredClass("scala.annotation.internal.$into")
@tu lazy val ErasedParamAnnot: ClassSymbol = requiredClass("scala.annotation.internal.ErasedParam")
@tu lazy val MainAnnot: ClassSymbol = requiredClass("scala.main")
@tu lazy val MappedAlternativeAnnot: ClassSymbol = requiredClass("scala.annotation.internal.MappedAlternative")
Expand Down Expand Up @@ -2137,7 +2136,6 @@ class Definitions {
orType,
RepeatedParamClass,
ByNameParamClass2x,
IntoType,
AnyValClass,
NullClass,
NothingClass,
Expand Down
2 changes: 1 addition & 1 deletion compiler/src/dotty/tools/dotc/core/StdNames.scala
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ object StdNames {
val EXCEPTION_RESULT_PREFIX: N = "exceptionResult"
val EXPAND_SEPARATOR: N = str.EXPAND_SEPARATOR
val IMPORT: N = "<import>"
val INTO: N = "<into>"
val INTO: N = "$into"
val MODULE_SUFFIX: N = str.MODULE_SUFFIX
val OPS_PACKAGE: N = "<special-ops>"
val OVERLOADED: N = "<overloaded>"
Expand Down
68 changes: 42 additions & 26 deletions compiler/src/dotty/tools/dotc/core/Types.scala
Original file line number Diff line number Diff line change
Expand Up @@ -419,8 +419,9 @@ object Types extends TypeUtils {
typeSymbol eq defn.RepeatedParamClass

/** Is this a parameter type that allows implicit argument converson? */
def isConvertibleParam(using Context): Boolean =
typeSymbol eq defn.IntoType
def isInto(using Context): Boolean = this match
case AnnotatedType(_, annot) => annot.symbol == defn.IntoParamAnnot
case _ => false

/** Is this the type of a method that has a repeated parameter type as
* last parameter type?
Expand Down Expand Up @@ -1927,7 +1928,9 @@ object Types extends TypeUtils {
case res => res
}
defn.FunctionNOf(
mt.paramInfos.mapConserve(_.translateFromRepeated(toArray = isJava)),
mt.paramInfos.mapConserve:
_.translateFromRepeated(toArray = isJava)
.mapIntoAnnot(defn.IntoParamAnnot, null),
result1, isContextual)
if mt.hasErasedParams then
defn.PolyFunctionOf(mt)
Expand Down Expand Up @@ -1975,6 +1978,38 @@ object Types extends TypeUtils {
case _ => this
}

/** A mapping between mapping one kind of into annotation to another or
* dropping into annotations.
* @param from the into annotation to map
* @param to either the replacement annotation symbol, or `null`
* in which case the `from` annotations are dropped.
*/
def mapIntoAnnot(from: ClassSymbol, to: ClassSymbol | Null)(using Context): Type = this match
case self @ AnnotatedType(tp, annot) =>
val tp1 = tp.mapIntoAnnot(from, to)
if annot.symbol == from then
if to == null then tp1
else AnnotatedType(tp1, Annotation(to, annot.tree.span))
else self.derivedAnnotatedType(tp1, annot)
case AppliedType(tycon, arg :: Nil) if tycon.typeSymbol == defn.RepeatedParamClass =>
val arg1 = arg.mapIntoAnnot(from, to)
if arg1 eq arg then this
else AppliedType(tycon, arg1 :: Nil)
case defn.FunctionOf(argTypes, resType, isContextual) =>
val resType1 = resType.mapIntoAnnot(from, to)
if resType1 eq resType then this
else defn.FunctionOf(argTypes, resType1, isContextual)
case RefinedType(parent, rname, mt: MethodOrPoly) =>
val mt1 = mt.mapIntoAnnot(from, to)
if mt1 eq mt then this
else RefinedType(parent.mapIntoAnnot(from, to), rname, mt1)
case mt: MethodOrPoly =>
mt.derivedLambdaType(resType = mt.resType.mapIntoAnnot(from, to))
case tp: ExprType =>
tp.derivedExprType(tp.resType.mapIntoAnnot(from, to))
case _ =>
this

/** A type capturing `ref` */
def capturing(ref: CaptureRef)(using Context): Type =
if captureSet.accountsFor(ref) then this
Expand Down Expand Up @@ -4122,6 +4157,7 @@ object Types extends TypeUtils {
/** Produce method type from parameter symbols, with special mappings for repeated
* and inline parameters:
* - replace @repeated annotations on Seq or Array types by <repeated> types
* - map into annotations to $into annotations
* - add @inlineParam to inline parameters
* - add @erasedParam to erased parameters
* - wrap types of parameters that have an @allowConversions annotation with Into[_]
Expand All @@ -4131,34 +4167,14 @@ object Types extends TypeUtils {
case ExprType(resType) => ExprType(addAnnotation(resType, cls, param))
case _ => AnnotatedType(tp, Annotation(cls, param.span))

def wrapConvertible(tp: Type) =
AppliedType(defn.IntoType.typeRef, tp :: Nil)

/** Add `Into[..] to the type itself and if it is a function type, to all its
* curried result type(s) as well.
*/
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.isFunctionNType(tp) =>
wrapConvertible(tp.derivedAppliedType(tycon, args.init :+ addInto(args.last)))
case tp @ defn.RefinedFunctionOf(rinfo) =>
wrapConvertible(tp.derivedRefinedType(refinedInfo = addInto(rinfo)))
case tp: MethodOrPoly =>
tp.derivedLambdaType(resType = addInto(tp.resType))
case ExprType(resType) =>
ExprType(addInto(resType))
case _ =>
wrapConvertible(tp)

def paramInfo(param: Symbol) =
var paramType = param.info.annotatedToRepeated
var paramType = param.info
.annotatedToRepeated
.mapIntoAnnot(defn.IntoAnnot, defn.IntoParamAnnot)
if param.is(Inline) then
paramType = addAnnotation(paramType, defn.InlineParamAnnot, param)
if param.is(Erased) then
paramType = addAnnotation(paramType, defn.ErasedParamAnnot, param)
if param.hasAnnotation(defn.AllowConversionsAnnot) then
paramType = addInto(paramType)
paramType

apply(params.map(_.name.asTermName))(
Expand Down
Loading