diff --git a/community-build/community-projects/intent b/community-build/community-projects/intent index 1436d2ca2439..38c7314fb764 160000 --- a/community-build/community-projects/intent +++ b/community-build/community-projects/intent @@ -1 +1 @@ -Subproject commit 1436d2ca243957d304ef43fd1f5d78f0e70cfcbf +Subproject commit 38c7314fb7643bc1786e4358b83a815194071d48 diff --git a/community-build/community-projects/shapeless b/community-build/community-projects/shapeless index dfa23f1ae4fe..3058735a54a2 160000 --- a/community-build/community-projects/shapeless +++ b/community-build/community-projects/shapeless @@ -1 +1 @@ -Subproject commit dfa23f1ae4fef5873d396ff32213c72274948dde +Subproject commit 3058735a54a23df67246ecce5b09f6a6cd3dfaec diff --git a/compiler/src-bootstrapped/scala/quoted/runtime/impl/QuotesImpl.scala b/compiler/src-bootstrapped/scala/quoted/runtime/impl/QuotesImpl.scala new file mode 100644 index 000000000000..b540f2bdc5a3 --- /dev/null +++ b/compiler/src-bootstrapped/scala/quoted/runtime/impl/QuotesImpl.scala @@ -0,0 +1,2889 @@ +package scala.quoted +package runtime.impl + +import dotty.tools.dotc +import dotty.tools.dotc.ast.tpd +import dotty.tools.dotc.ast.untpd +import dotty.tools.dotc.core.Annotations +import dotty.tools.dotc.core.Contexts._ +import dotty.tools.dotc.core.Types +import dotty.tools.dotc.core.Flags._ +import dotty.tools.dotc.core.NameKinds +import dotty.tools.dotc.core.StdNames._ +import dotty.tools.dotc.quoted.reflect._ +import dotty.tools.dotc.quoted.QuoteUtils._ +import dotty.tools.dotc.core.Decorators._ + +import dotty.tools.dotc.quoted.{MacroExpansion, PickledQuotes, QuoteUtils} + +import scala.quoted.runtime.{QuoteUnpickler, QuoteMatching} +import scala.quoted.runtime.impl.printers._ + +import scala.reflect.TypeTest + +object QuotesImpl { + + type ScopeId = Int + + def apply()(using Context): Quotes = + new QuotesImpl + + def showDecompiledTree(tree: tpd.Tree)(using Context): String = + import qctx.reflect.Printer.{TreeCode, TreeAnsiCode} + val qctx: QuotesImpl = new QuotesImpl(using MacroExpansion.context(tree)) + if ctx.settings.color.value == "always" then TreeAnsiCode.show(tree) + else TreeCode.show(tree) + + // TODO Explore more fine grained scope ids. + // This id can only differentiate scope extrusion from one compiler instance to another. + def scopeId(using Context): ScopeId = + ctx.outersIterator.toList.last.hashCode() + +} + +class QuotesImpl private (using val ctx: Context) extends Quotes, QuoteUnpickler, QuoteMatching: + + private val yCheck: Boolean = + ctx.settings.Ycheck.value(using ctx).exists(x => x == "all" || x == "macros") + + extension [T](self: scala.quoted.Expr[T]) + def show: String = + reflect.Printer.TreeCode.show(reflect.asTerm(self)) + + def matches(that: scala.quoted.Expr[Any]): Boolean = + treeMatch(reflect.asTerm(self), reflect.asTerm(that)).nonEmpty + + end extension + + extension (self: scala.quoted.Expr[Any]) + /** Checks is the `quoted.Expr[?]` is valid expression of type `X` */ + def isExprOf[X](using scala.quoted.Type[X]): Boolean = + reflect.TypeReprMethods.<:<(reflect.asTerm(self).tpe)(reflect.TypeRepr.of[X]) + + /** Convert this to an `quoted.Expr[X]` if this expression is a valid expression of type `X` or throws */ + def asExprOf[X](using scala.quoted.Type[X]): scala.quoted.Expr[X] = { + if self.isExprOf[X] then + self.asInstanceOf[scala.quoted.Expr[X]] + else + throw Exception( + s"""Expr cast exception: ${self.show} + |of type: ${reflect.Printer.TypeReprCode.show(reflect.asTerm(self).tpe)} + |did not conform to type: ${reflect.Printer.TypeReprCode.show(reflect.TypeRepr.of[X])} + |""".stripMargin + ) + } + end extension + + object reflect extends reflectModule: + + extension (expr: Expr[Any]) + def asTerm: Term = + val exprImpl = expr.asInstanceOf[ExprImpl] + exprImpl.checkScopeId(QuotesImpl.this.hashCode) + exprImpl.tree + end extension + + type Tree = tpd.Tree + + object Tree extends TreeModule + + given TreeMethods: TreeMethods with + extension (self: Tree) + def pos: Position = self.sourcePos + def symbol: Symbol = self.symbol + def show(using printer: Printer[Tree]): String = printer.show(self) + def isExpr: Boolean = + self match + case TermTypeTest(self) => + self.tpe.widen match + case _: MethodType | _: PolyType => false + case _ => true + case _ => false + def asExpr: scala.quoted.Expr[Any] = + if self.isExpr then + new ExprImpl(self, QuotesImpl.this.hashCode) + else self match + case TermTypeTest(self) => throw new Exception("Expected an expression. This is a partially applied Term. Try eta-expanding the term first.") + case _ => throw new Exception("Expected a Term but was: " + self) + end extension + + extension (self: Tree) + def asExprOf[T](using tp: scala.quoted.Type[T]): scala.quoted.Expr[T] = + QuotesImpl.this.asExprOf(self.asExpr)[T](using tp) + end extension + + extension [ThisTree <: Tree](self: ThisTree) + def changeOwner(newOwner: Symbol): ThisTree = + tpd.TreeOps(self).changeNonLocalOwners(newOwner).asInstanceOf[ThisTree] + end extension + + end TreeMethods + + type PackageClause = tpd.PackageDef + + object PackageClauseTypeTest extends TypeTest[Tree, PackageClause]: + def unapply(x: Tree): Option[PackageClause & x.type] = x match + case x: (tpd.PackageDef & x.type) => Some(x) + case _ => None + end PackageClauseTypeTest + + object PackageClause extends PackageClauseModule: + def apply(pid: Ref, stats: List[Tree]): PackageClause = + withDefaultPos(tpd.PackageDef(pid.asInstanceOf[tpd.RefTree], stats)) + def copy(original: Tree)(pid: Ref, stats: List[Tree]): PackageClause = + tpd.cpy.PackageDef(original)(pid, stats) + def unapply(tree: PackageClause): (Ref, List[Tree]) = + (tree.pid, tree.stats) + end PackageClause + + given PackageClauseMethods: PackageClauseMethods with + extension (self: PackageClause) + def pid: Ref = self.pid + def stats: List[Tree] = self.stats + end extension + end PackageClauseMethods + + type Import = tpd.Import + + object ImportTypeTest extends TypeTest[Tree, Import]: + def unapply(x: Tree): Option[Import & x.type] = x match + case tree: (tpd.Import & x.type) => Some(tree) + case _ => None + end ImportTypeTest + + object Import extends ImportModule: + def apply(expr: Term, selectors: List[Selector]): Import = + withDefaultPos(tpd.Import(expr, selectors)) + def copy(original: Tree)(expr: Term, selectors: List[Selector]): Import = + tpd.cpy.Import(original)(expr, selectors) + def unapply(tree: Import): (Term, List[Selector]) = + (tree.expr, tree.selectors) + end Import + + given ImportMethods: ImportMethods with + extension (self: Import) + def expr: Term = self.expr + def selectors: List[Selector] = self.selectors + end extension + end ImportMethods + + type Export = tpd.Export + + object ExportTypeTest extends TypeTest[Tree, Export]: + def unapply(x: Tree): Option[Export & x.type] = x match + case tree: (tpd.Export & x.type) => Some(tree) + case _ => None + end ExportTypeTest + + object Export extends ExportModule: + def unapply(tree: Export): (Term, List[Selector]) = + (tree.expr, tree.selectors) + end Export + + given ExportMethods: ExportMethods with + extension (self: Export) + def expr: Term = self.expr + def selectors: List[Selector] = self.selectors + end extension + end ExportMethods + + type Statement = tpd.Tree + + object StatementTypeTest extends TypeTest[Tree, Statement]: + def unapply(x: Tree): Option[Statement & x.type] = x match + case _: tpd.PatternTree => None + case _ => + if x.isTerm then TermTypeTest.unapply(x) + else DefinitionTypeTest.unapply(x) + end StatementTypeTest + + type Definition = tpd.MemberDef + + object DefinitionTypeTest extends TypeTest[Tree, Definition]: + def unapply(x: Tree): Option[Definition & x.type] = x match + case x: (tpd.MemberDef & x.type) => Some(x) + case _ => None + end DefinitionTypeTest + + object Definition extends DefinitionModule + + given DefinitionMethods: DefinitionMethods with + extension (self: Definition) + def name: String = self match + case self: tpd.MemberDef => self.name.toString + end extension + end DefinitionMethods + + type ClassDef = tpd.TypeDef + + object ClassDefTypeTest extends TypeTest[Tree, ClassDef]: + def unapply(x: Tree): Option[ClassDef & x.type] = x match + case x: (tpd.TypeDef & x.type) if x.isClassDef => Some(x) + case _ => None + end ClassDefTypeTest + + object ClassDef extends ClassDefModule: + def copy(original: Tree)(name: String, constr: DefDef, parents: List[Tree], derived: List[TypeTree], selfOpt: Option[ValDef], body: List[Statement]): ClassDef = { + val dotc.ast.Trees.TypeDef(_, originalImpl: tpd.Template) = original + tpd.cpy.TypeDef(original)(name.toTypeName, tpd.cpy.Template(originalImpl)(constr, parents, derived, selfOpt.getOrElse(tpd.EmptyValDef), body)) + } + def unapply(cdef: ClassDef): (String, DefDef, List[Tree /* Term | TypeTree */], List[TypeTree], Option[ValDef], List[Statement]) = + val rhs = cdef.rhs.asInstanceOf[tpd.Template] + (cdef.name.toString, cdef.constructor, cdef.parents, rhs.derived.asInstanceOf[List[TypeTree]], cdef.self, rhs.body) + end ClassDef + + given ClassDefMethods: ClassDefMethods with + extension (self: ClassDef) + def constructor: DefDef = + self.rhs.asInstanceOf[tpd.Template].constr + def parents: List[Tree] = + self.rhs.asInstanceOf[tpd.Template].parents + def derived: List[TypeTree] = + self.rhs.asInstanceOf[tpd.Template].derived.asInstanceOf[List[TypeTree]] + def self: Option[ValDef] = + optional(self.rhs.asInstanceOf[tpd.Template].self) + def body: List[Statement] = + self.rhs.asInstanceOf[tpd.Template].body + end extension + end ClassDefMethods + + type DefDef = tpd.DefDef + + object DefDefTypeTest extends TypeTest[Tree, DefDef]: + def unapply(x: Tree): Option[DefDef & x.type] = x match + case x: (tpd.DefDef & x.type) => Some(x) + case _ => None + end DefDefTypeTest + + object DefDef extends DefDefModule: + def apply(symbol: Symbol, rhsFn: List[TypeRepr] => List[List[Term]] => Option[Term]): DefDef = + withDefaultPos(tpd.DefDef(symbol.asTerm, prefss => { + val (tparams, vparamss) = tpd.splitArgs(prefss) + yCheckedOwners(rhsFn(tparams.map(_.tpe))(vparamss), symbol).getOrElse(tpd.EmptyTree) + })) + def copy(original: Tree)(name: String, typeParams: List[TypeDef], paramss: List[List[ValDef]], tpt: TypeTree, rhs: Option[Term]): DefDef = + tpd.cpy.DefDef(original)(name.toTermName, tpd.joinParams(typeParams, paramss), tpt, yCheckedOwners(rhs, original.symbol).getOrElse(tpd.EmptyTree)) + def unapply(ddef: DefDef): (String, List[TypeDef], List[List[ValDef]], TypeTree, Option[Term]) = + (ddef.name.toString, ddef.typeParams, ddef.termParamss, ddef.tpt, optional(ddef.rhs)) + end DefDef + + given DefDefMethods: DefDefMethods with + extension (self: DefDef) + def typeParams: List[TypeDef] = self.leadingTypeParams // TODO: adapt to multiple type parameter clauses + def paramss: List[List[ValDef]] = self.termParamss + def returnTpt: TypeTree = self.tpt + def rhs: Option[Term] = optional(self.rhs) + end extension + end DefDefMethods + + type ValDef = tpd.ValDef + + object ValDefTypeTest extends TypeTest[Tree, ValDef]: + def unapply(x: Tree): Option[ValDef & x.type] = x match + case x: (tpd.ValDef & x.type) => Some(x) + case _ => None + end ValDefTypeTest + + object ValDef extends ValDefModule: + def apply(symbol: Symbol, rhs: Option[Term]): ValDef = + tpd.ValDef(symbol.asTerm, yCheckedOwners(rhs, symbol).getOrElse(tpd.EmptyTree)) + def copy(original: Tree)(name: String, tpt: TypeTree, rhs: Option[Term]): ValDef = + tpd.cpy.ValDef(original)(name.toTermName, tpt, yCheckedOwners(rhs, original.symbol).getOrElse(tpd.EmptyTree)) + def unapply(vdef: ValDef): (String, TypeTree, Option[Term]) = + (vdef.name.toString, vdef.tpt, optional(vdef.rhs)) + + def let(owner: Symbol, name: String, rhs: Term)(body: Ident => Term): Term = + val vdef = tpd.SyntheticValDef(name.toTermName, rhs)(using ctx.withOwner(owner)) + val ref = tpd.ref(vdef.symbol).asInstanceOf[Ident] + Block(List(vdef), body(ref)) + + def let(owner: Symbol, terms: List[Term])(body: List[Ident] => Term): Term = + val ctx1 = ctx.withOwner(owner) + val vdefs = terms.map(term => tpd.SyntheticValDef("x".toTermName, term)(using ctx1)) + val refs = vdefs.map(vdef => tpd.ref(vdef.symbol).asInstanceOf[Ident]) + Block(vdefs, body(refs)) + end ValDef + + given ValDefMethods: ValDefMethods with + extension (self: ValDef) + def tpt: TypeTree = self.tpt + def rhs: Option[Term] = optional(self.rhs) + end extension + end ValDefMethods + + type TypeDef = tpd.TypeDef + + object TypeDefTypeTest extends TypeTest[Tree, TypeDef]: + def unapply(x: Tree): Option[TypeDef & x.type] = x match + case x: (tpd.TypeDef & x.type) if !x.isClassDef => Some(x) + case _ => None + end TypeDefTypeTest + + object TypeDef extends TypeDefModule: + def apply(symbol: Symbol): TypeDef = + withDefaultPos(tpd.TypeDef(symbol.asType)) + def copy(original: Tree)(name: String, rhs: Tree): TypeDef = + tpd.cpy.TypeDef(original)(name.toTypeName, rhs) + def unapply(tdef: TypeDef): (String, Tree /*TypeTree | TypeBoundsTree*/ /* TypeTree | TypeBoundsTree */) = + (tdef.name.toString, tdef.rhs) + end TypeDef + + given TypeDefMethods: TypeDefMethods with + extension (self: TypeDef) + def rhs: Tree = self.rhs + end extension + end TypeDefMethods + + type Term = tpd.Tree + + object TermTypeTest extends TypeTest[Tree, Term]: + def unapply(x: Tree): Option[Term & x.type] = x match + case _ if UnapplyTypeTest.unapply(x).isDefined => None + case _: tpd.PatternTree => None + case x: (tpd.Tree & x.type) if x.isTerm => Some(x) + case x: (tpd.SeqLiteral & x.type) => Some(x) + case x: (tpd.Inlined & x.type) => Some(x) + case x: (tpd.NamedArg & x.type) => Some(x) + case _ => None + end TermTypeTest + + object Term extends TermModule: + def betaReduce(tree: Term): Option[Term] = + tree match + case app @ tpd.Apply(tpd.Select(fn, nme.apply), args) if dotc.core.Symbols.defn.isFunctionType(fn.tpe) => + val app1 = dotc.transform.BetaReduce(app, fn, args) + if app1 eq app then None + else Some(app1.withSpan(tree.span)) + case tpd.Block(Nil, expr) => + for e <- betaReduce(expr) yield tpd.cpy.Block(tree)(Nil, e) + case tpd.Inlined(_, Nil, expr) => + betaReduce(expr) + case _ => + None + end Term + + given TermMethods: TermMethods with + extension (self: Term) + def seal: scala.quoted.Expr[Any] = + if self.isExpr then new ExprImpl(self, QuotesImpl.this.hashCode) + else throw new Exception("Cannot seal a partially applied Term. Try eta-expanding the term first.") + + def sealOpt: Option[scala.quoted.Expr[Any]] = + if self.isExpr then Some(new ExprImpl(self, QuotesImpl.this.hashCode)) + else None + + def tpe: TypeRepr = self.tpe + def underlyingArgument: Term = new tpd.TreeOps(self).underlyingArgument + def underlying: Term = new tpd.TreeOps(self).underlying + def etaExpand(owner: Symbol): Term = self.tpe.widen match { + case mtpe: Types.MethodType if !mtpe.isParamDependent => + val closureResType = mtpe.resType match { + case t: Types.MethodType => t.toFunctionType() + case t => t + } + val closureTpe = Types.MethodType(mtpe.paramNames, mtpe.paramInfos, closureResType) + val closureMethod = dotc.core.Symbols.newSymbol(owner, nme.ANON_FUN, Synthetic | Method, closureTpe) + tpd.Closure(closureMethod, tss => new tpd.TreeOps(self).appliedToTermArgs(tss.head).etaExpand(closureMethod)) + case _ => self + } + + def appliedTo(arg: Term): Term = + self.appliedToArgs(arg :: Nil) + def appliedTo(arg: Term, args: Term*): Term = + self.appliedToArgs(arg :: args.toList) + def appliedToArgs(args: List[Term]): Apply = + Apply(self, args) + def appliedToArgss(argss: List[List[Term]]): Term = + argss.foldLeft(self: Term)(Apply(_, _)) + def appliedToNone: Apply = + self.appliedToArgs(Nil) + def appliedToType(targ: TypeRepr): Term = + self.appliedToTypes(targ :: Nil) + def appliedToTypes(targs: List[TypeRepr]): Term = + self.appliedToTypeTrees(targs map (Inferred(_))) + def appliedToTypeTrees(targs: List[TypeTree]): Term = + if (targs.isEmpty) self else TypeApply(self, targs) + def select(sym: Symbol): Select = Select(self, sym) + + end extension + end TermMethods + + type Ref = tpd.RefTree + + object RefTypeTest extends TypeTest[Tree, Ref]: + def unapply(x: Tree): Option[Ref & x.type] = x match + case x: (tpd.RefTree & x.type) if x.isTerm => Some(x) + case _ => None + end RefTypeTest + + object Ref extends RefModule: + def term(tp: TermRef): Ref = + withDefaultPos(tpd.ref(tp).asInstanceOf[tpd.RefTree]) + def apply(sym: Symbol): Ref = + assert(sym.isTerm) + withDefaultPos(tpd.ref(sym).asInstanceOf[tpd.RefTree]) + end Ref + + type Ident = tpd.Ident + + object IdentTypeTest extends TypeTest[Tree, Ident]: + def unapply(x: Tree): Option[Ident & x.type] = x match + case x: (tpd.Ident & x.type) if x.isTerm => Some(x) + case _ => None + end IdentTypeTest + + object Ident extends IdentModule: + def apply(tmref: TermRef): Term = + withDefaultPos(tpd.ref(tmref).asInstanceOf[Term]) + def copy(original: Tree)(name: String): Ident = + tpd.cpy.Ident(original)(name.toTermName) + def unapply(tree: Ident): Some[String] = + Some(tree.name.toString) + end Ident + + given IdentMethods: IdentMethods with + extension (self: Ident) + def name: String = self.name.toString + end extension + end IdentMethods + + type Select = tpd.Select + + object SelectTypeTest extends TypeTest[Tree, Select]: + def unapply(x: Tree): Option[Select & x.type] = x match + case x: (tpd.Select & x.type) if x.isTerm => Some(x) + case _ => None + end SelectTypeTest + + object Select extends SelectModule: + def apply(qualifier: Term, symbol: Symbol): Select = + withDefaultPos(tpd.Select(qualifier, Types.TermRef(qualifier.tpe, symbol))) + def unique(qualifier: Term, name: String): Select = + val denot = qualifier.tpe.member(name.toTermName) + assert(!denot.isOverloaded, s"The symbol `$name` is overloaded. The method Select.unique can only be used for non-overloaded symbols.") + withDefaultPos(tpd.Select(qualifier, name.toTermName)) + def overloaded(qualifier: Term, name: String, targs: List[TypeRepr], args: List[Term]): Apply = + withDefaultPos(tpd.applyOverloaded(qualifier, name.toTermName, args, targs, Types.WildcardType).asInstanceOf[Apply]) + + def overloaded(qualifier: Term, name: String, targs: List[TypeRepr], args: List[Term], returnType: TypeRepr): Apply = + withDefaultPos(tpd.applyOverloaded(qualifier, name.toTermName, args, targs, returnType).asInstanceOf[Apply]) + def copy(original: Tree)(qualifier: Term, name: String): Select = + tpd.cpy.Select(original)(qualifier, name.toTermName) + def unapply(x: Select): (Term, String) = + (x.qualifier, x.name.toString) + end Select + + given SelectMethods: SelectMethods with + extension (self: Select) + def qualifier: Term = self.qualifier + def name: String = self.name.toString + def signature: Option[Signature] = + if self.symbol.signature == dotc.core.Signature.NotAMethod then None + else Some(self.symbol.signature) + end extension + end SelectMethods + + type Literal = tpd.Literal + + object LiteralTypeTest extends TypeTest[Tree, Literal]: + def unapply(x: Tree): Option[Literal & x.type] = x match + case x: (tpd.Literal & x.type) => Some(x) + case _ => None + end LiteralTypeTest + + object Literal extends LiteralModule: + def apply(constant: Constant): Literal = + withDefaultPos(tpd.Literal(constant)) + def copy(original: Tree)(constant: Constant): Literal = + tpd.cpy.Literal(original)(constant) + def unapply(x: Literal): Some[Constant] = + Some(x.constant) + end Literal + + given LiteralMethods: LiteralMethods with + extension (self: Literal) + def constant: Constant = self.const + end extension + end LiteralMethods + + type This = tpd.This + + object ThisTypeTest extends TypeTest[Tree, This]: + def unapply(x: Tree): Option[This & x.type] = x match + case x: (tpd.This & x.type) => Some(x) + case _ => None + end ThisTypeTest + + object This extends ThisModule: + def apply(cls: Symbol): This = + withDefaultPos(tpd.This(cls.asClass)) + def copy(original: Tree)(qual: Option[String]): This = + tpd.cpy.This(original)(qual.map(x => untpd.Ident(x.toTypeName)).getOrElse(untpd.EmptyTypeIdent)) + def unapply(x: This): Some[Option[String]] = + Some(optional(x.qual).map(_.name.toString)) + end This + + given ThisMethods: ThisMethods with + extension (self: This) + def id: Option[String] = optional(self.qual).map(_.name.toString) + end extension + end ThisMethods + + type New = tpd.New + + object NewTypeTest extends TypeTest[Tree, New]: + def unapply(x: Tree): Option[New & x.type] = x match + case x: (tpd.New & x.type) => Some(x) + case _ => None + end NewTypeTest + + object New extends NewModule: + def apply(tpt: TypeTree): New = + withDefaultPos(tpd.New(tpt)) + def copy(original: Tree)(tpt: TypeTree): New = + tpd.cpy.New(original)(tpt) + def unapply(x: New): Some[TypeTree] = Some(x.tpt) + end New + + given NewMethods: NewMethods with + extension (self: New) + def tpt: TypeTree = self.tpt + end extension + end NewMethods + + type NamedArg = tpd.NamedArg + + object NamedArgTypeTest extends TypeTest[Tree, NamedArg]: + def unapply(x: Tree): Option[NamedArg & x.type] = x match + case x: (tpd.NamedArg & x.type) if x.name.isInstanceOf[dotc.core.Names.TermName] => Some(x) // TODO: Now, the name should alwas be a term name + case _ => None + end NamedArgTypeTest + + object NamedArg extends NamedArgModule: + def apply(name: String, arg: Term): NamedArg = + withDefaultPos(tpd.NamedArg(name.toTermName, arg)) + def copy(original: Tree)(name: String, arg: Term): NamedArg = + tpd.cpy.NamedArg(original)(name.toTermName, arg) + def unapply(x: NamedArg): (String, Term) = + (x.name.toString, x.value) + end NamedArg + + given NamedArgMethods: NamedArgMethods with + extension (self: NamedArg) + def name: String = self.name.toString + def value: Term = self.arg + end extension + end NamedArgMethods + + type Apply = tpd.Apply + + object ApplyTypeTest extends TypeTest[Tree, Apply]: + def unapply(x: Tree): Option[Apply & x.type] = x match + case x: (tpd.Apply & x.type) => Some(x) + case _ => None + end ApplyTypeTest + + object Apply extends ApplyModule: + def apply(fun: Term, args: List[Term]): Apply = + withDefaultPos(tpd.Apply(fun, args)) + def copy(original: Tree)(fun: Term, args: List[Term]): Apply = + tpd.cpy.Apply(original)(fun, args) + def unapply(x: Apply): (Term, List[Term]) = + (x.fun, x.args) + end Apply + + given ApplyMethods: ApplyMethods with + extension (self: Apply) + def fun: Term = self.fun + def args: List[Term] = self.args + end extension + end ApplyMethods + + type TypeApply = tpd.TypeApply + + object TypeApplyTypeTest extends TypeTest[Tree, TypeApply]: + def unapply(x: Tree): Option[TypeApply & x.type] = x match + case x: (tpd.TypeApply & x.type) => Some(x) + case _ => None + end TypeApplyTypeTest + + object TypeApply extends TypeApplyModule: + def apply(fun: Term, args: List[TypeTree]): TypeApply = + withDefaultPos(tpd.TypeApply(fun, args)) + def copy(original: Tree)(fun: Term, args: List[TypeTree]): TypeApply = + tpd.cpy.TypeApply(original)(fun, args) + def unapply(x: TypeApply): (Term, List[TypeTree]) = + (x.fun, x.args) + end TypeApply + + given TypeApplyMethods: TypeApplyMethods with + extension (self: TypeApply) + def fun: Term = self.fun + def args: List[TypeTree] = self.args + end extension + end TypeApplyMethods + + type Super = tpd.Super + + object SuperTypeTest extends TypeTest[Tree, Super]: + def unapply(x: Tree): Option[Super & x.type] = x match + case x: (tpd.Super & x.type) => Some(x) + case _ => None + end SuperTypeTest + + object Super extends SuperModule: + def apply(qual: Term, mix: Option[String]): Super = + withDefaultPos(tpd.Super(qual, mix.map(x => untpd.Ident(x.toTypeName)).getOrElse(untpd.EmptyTypeIdent), dotc.core.Symbols.NoSymbol)) + def copy(original: Tree)(qual: Term, mix: Option[String]): Super = + tpd.cpy.Super(original)(qual, mix.map(x => untpd.Ident(x.toTypeName)).getOrElse(untpd.EmptyTypeIdent)) + def unapply(x: Super): (Term, Option[String]) = + (x.qualifier, x.id) + end Super + + given SuperMethods: SuperMethods with + extension (self: Super) + def qualifier: Term = self.qual + def id: Option[String] = optional(self.mix).map(_.name.toString) + def idPos: Position = self.mix.sourcePos + end extension + end SuperMethods + + type Typed = tpd.Typed + + object TypedTypeTest extends TypeTest[Tree, Typed]: + def unapply(x: Tree): Option[Typed & x.type] = x match + case x: (tpd.Typed & x.type) => Some(x) + case _ => None + end TypedTypeTest + + object Typed extends TypedModule: + def apply(expr: Term, tpt: TypeTree): Typed = + withDefaultPos(tpd.Typed(expr, tpt)) + def copy(original: Tree)(expr: Term, tpt: TypeTree): Typed = + tpd.cpy.Typed(original)(expr, tpt) + def unapply(x: Typed): (Term, TypeTree) = + (x.expr, x.tpt) + end Typed + + given TypedMethods: TypedMethods with + extension (self: Typed) + def expr: Term = self.expr + def tpt: TypeTree = self.tpt + end extension + end TypedMethods + + type Assign = tpd.Assign + + object AssignTypeTest extends TypeTest[Tree, Assign]: + def unapply(x: Tree): Option[Assign & x.type] = x match + case x: (tpd.Assign & x.type) => Some(x) + case _ => None + end AssignTypeTest + + object Assign extends AssignModule: + def apply(lhs: Term, rhs: Term): Assign = + withDefaultPos(tpd.Assign(lhs, rhs)) + def copy(original: Tree)(lhs: Term, rhs: Term): Assign = + tpd.cpy.Assign(original)(lhs, rhs) + def unapply(x: Assign): (Term, Term) = + (x.lhs, x.rhs) + end Assign + + given AssignMethods: AssignMethods with + extension (self: Assign) + def lhs: Term = self.lhs + def rhs: Term = self.rhs + end extension + end AssignMethods + + type Block = tpd.Block + + object BlockTypeTest extends TypeTest[Tree, Block]: + def unapply(x: Tree): Option[Block & x.type] = x match + case x: (tpd.Block & x.type) => Some(x) + case _ => None + end BlockTypeTest + + object Block extends BlockModule: + def apply(stats: List[Statement], expr: Term): Block = + withDefaultPos(tpd.Block(stats, expr)) + def copy(original: Tree)(stats: List[Statement], expr: Term): Block = + tpd.cpy.Block(original)(stats, expr) + def unapply(x: Block): (List[Statement], Term) = + (x.statements, x.expr) + end Block + + given BlockMethods: BlockMethods with + extension (self: Block) + def statements: List[Statement] = self.stats + def expr: Term = self.expr + end extension + end BlockMethods + + type Closure = tpd.Closure + + object ClosureTypeTest extends TypeTest[Tree, Closure]: + def unapply(x: Tree): Option[Closure & x.type] = x match + case x: (tpd.Closure & x.type) => Some(x) + case _ => None + end ClosureTypeTest + + object Closure extends ClosureModule: + def apply(meth: Term, tpe: Option[TypeRepr]): Closure = + withDefaultPos(tpd.Closure(Nil, meth, tpe.map(tpd.TypeTree(_)).getOrElse(tpd.EmptyTree))) + def copy(original: Tree)(meth: Tree, tpe: Option[TypeRepr]): Closure = + tpd.cpy.Closure(original)(Nil, meth, tpe.map(tpd.TypeTree(_)).getOrElse(tpd.EmptyTree)) + def unapply(x: Closure): (Term, Option[TypeRepr]) = + (x.meth, x.tpeOpt) + end Closure + + given ClosureMethods: ClosureMethods with + extension (self: Closure) + def meth: Term = self.meth + def tpeOpt: Option[TypeRepr] = optional(self.tpt).map(_.tpe) + end extension + end ClosureMethods + + object Lambda extends LambdaModule: + def apply(owner: Symbol, tpe: MethodType, rhsFn: (Symbol, List[Tree]) => Tree): Block = + val meth = dotc.core.Symbols.newSymbol(owner, nme.ANON_FUN, Synthetic | Method, tpe) + tpd.Closure(meth, tss => yCheckedOwners(rhsFn(meth, tss.head), meth)) + + def unapply(tree: Block): Option[(List[ValDef], Term)] = tree match { + case Block((ddef @ DefDef(_, _, params :: Nil, _, Some(body))) :: Nil, Closure(meth, _)) + if ddef.symbol == meth.symbol => + Some((params, body)) + case _ => None + } + end Lambda + + type If = tpd.If + + object IfTypeTest extends TypeTest[Tree, If]: + def unapply(x: Tree): Option[If & x.type] = x match + case x: (tpd.If & x.type) => Some(x) + case _ => None + end IfTypeTest + + object If extends IfModule: + def apply(cond: Term, thenp: Term, elsep: Term): If = + withDefaultPos(tpd.If(cond, thenp, elsep)) + def copy(original: Tree)(cond: Term, thenp: Term, elsep: Term): If = + tpd.cpy.If(original)(cond, thenp, elsep) + def unapply(tree: If): (Term, Term, Term) = + (tree.cond, tree.thenp, tree.elsep) + end If + + given IfMethods: IfMethods with + extension (self: If) + def cond: Term = self.cond + def thenp: Term = self.thenp + def elsep: Term = self.elsep + def isInline: Boolean = self.isInline + end extension + end IfMethods + + type Match = tpd.Match + + object MatchTypeTest extends TypeTest[Tree, Match]: + def unapply(x: Tree): Option[Match & x.type] = x match + case x: (tpd.Match & x.type) if !x.selector.isEmpty => Some(x) + case _ => None + end MatchTypeTest + + object Match extends MatchModule: + def apply(selector: Term, cases: List[CaseDef]): Match = + withDefaultPos(tpd.Match(selector, cases)) + + def copy(original: Tree)(selector: Term, cases: List[CaseDef]): Match = + tpd.cpy.Match(original)(selector, cases) + + def unapply(x: Match): (Term, List[CaseDef]) = + (x.scrutinee, x.cases) + end Match + + given MatchMethods: MatchMethods with + extension (self: Match) + def scrutinee: Term = self.selector + def cases: List[CaseDef] = self.cases + def isInline: Boolean = self.isInline + end extension + end MatchMethods + + type SummonFrom = tpd.Match + + object SummonFromTypeTest extends TypeTest[Tree, SummonFrom]: + def unapply(x: Tree): Option[SummonFrom & x.type] = x match + case x: (tpd.Match & x.type) if x.selector.isEmpty => Some(x) + case _ => None + end SummonFromTypeTest + + object SummonFrom extends SummonFromModule: + def apply(cases: List[CaseDef]): SummonFrom = + withDefaultPos(tpd.Match(tpd.EmptyTree, cases)) + def copy(original: Tree)(cases: List[CaseDef]): SummonFrom = + tpd.cpy.Match(original)(tpd.EmptyTree, cases) + def unapply(x: SummonFrom): Some[List[CaseDef]] = + Some(x.cases) + end SummonFrom + + given SummonFromMethods: SummonFromMethods with + extension (self: SummonFrom) + def cases: List[CaseDef] = self.cases + end extension + end SummonFromMethods + + type Try = tpd.Try + + object TryTypeTest extends TypeTest[Tree, Try]: + def unapply(x: Tree): Option[Try & x.type] = x match + case x: (tpd.Try & x.type) => Some(x) + case _ => None + end TryTypeTest + + object Try extends TryModule: + def apply(expr: Term, cases: List[CaseDef], finalizer: Option[Term]): Try = + withDefaultPos(tpd.Try(expr, cases, finalizer.getOrElse(tpd.EmptyTree))) + def copy(original: Tree)(expr: Term, cases: List[CaseDef], finalizer: Option[Term]): Try = + tpd.cpy.Try(original)(expr, cases, finalizer.getOrElse(tpd.EmptyTree)) + def unapply(x: Try): (Term, List[CaseDef], Option[Term]) = + (x.body, x.cases, optional(x.finalizer)) + end Try + + given TryMethods: TryMethods with + extension (self: Try) + def body: Term = self.expr + def cases: List[CaseDef] = self.cases + def finalizer: Option[Term] = optional(self.finalizer) + end extension + end TryMethods + + type Return = tpd.Return + + object ReturnTypeTest extends TypeTest[Tree, Return]: + def unapply(x: Tree): Option[Return & x.type] = x match + case x: (tpd.Return & x.type) => Some(x) + case _ => None + end ReturnTypeTest + + object Return extends ReturnModule: + def apply(expr: Term, from: Symbol): Return = + withDefaultPos(tpd.Return(expr, from)) + def copy(original: Tree)(expr: Term, from: Symbol): Return = + tpd.cpy.Return(original)(expr, tpd.ref(from)) + def unapply(x: Return): (Term, Symbol) = + (x.expr, x.from.symbol) + end Return + + given ReturnMethods: ReturnMethods with + extension (self: Return) + def expr: Term = self.expr + def from: Symbol = self.from.symbol + end extension + end ReturnMethods + + type Repeated = tpd.SeqLiteral + + object RepeatedTypeTest extends TypeTest[Tree, Repeated]: + def unapply(x: Tree): Option[Repeated & x.type] = x match + case x: (tpd.SeqLiteral & x.type) => Some(x) + case _ => None + end RepeatedTypeTest + + object Repeated extends RepeatedModule: + def apply(elems: List[Term], elemtpt: TypeTree): Repeated = + withDefaultPos(tpd.SeqLiteral(elems, elemtpt)) + def copy(original: Tree)(elems: List[Term], elemtpt: TypeTree): Repeated = + tpd.cpy.SeqLiteral(original)(elems, elemtpt) + def unapply(x: Repeated): (List[Term], TypeTree) = + (x.elems, x.elemtpt) + end Repeated + + given RepeatedMethods: RepeatedMethods with + extension (self: Repeated) + def elems: List[Term] = self.elems + def elemtpt: TypeTree = self.elemtpt + end extension + end RepeatedMethods + + type Inlined = tpd.Inlined + + object InlinedTypeTest extends TypeTest[Tree, Inlined]: + def unapply(x: Tree): Option[Inlined & x.type] = x match + case x: (tpd.Inlined & x.type) => Some(x) + case _ => None + end InlinedTypeTest + + object Inlined extends InlinedModule: + def apply(call: Option[Tree], bindings: List[Definition], expansion: Term): Inlined = + withDefaultPos(tpd.Inlined(call.getOrElse(tpd.EmptyTree), bindings.map { case b: tpd.MemberDef => b }, expansion)) + def copy(original: Tree)(call: Option[Tree], bindings: List[Definition], expansion: Term): Inlined = + tpd.cpy.Inlined(original)(call.getOrElse(tpd.EmptyTree), bindings.asInstanceOf[List[tpd.MemberDef]], expansion) + def unapply(x: Inlined): (Option[Tree /* Term | TypeTree */], List[Definition], Term) = + (optional(x.call), x.bindings, x.body) + end Inlined + + given InlinedMethods: InlinedMethods with + extension (self: Inlined) + def call: Option[Tree] = optional(self.call) + def bindings: List[Definition] = self.bindings + def body: Term = self.expansion + end extension + end InlinedMethods + + type SelectOuter = tpd.Select + + object SelectOuterTypeTest extends TypeTest[Tree, SelectOuter]: + def unapply(x: Tree): Option[SelectOuter & x.type] = x match + case x: (tpd.Select & x.type) => + x.name match + case NameKinds.OuterSelectName(_, _) => Some(x) + case _ => None + case _ => None + end SelectOuterTypeTest + + object SelectOuter extends SelectOuterModule: + def apply(qualifier: Term, name: String, levels: Int): SelectOuter = + withDefaultPos(tpd.Select(qualifier, NameKinds.OuterSelectName(name.toTermName, levels))) + def copy(original: Tree)(qualifier: Term, name: String, levels: Int): SelectOuter = + tpd.cpy.Select(original)(qualifier, NameKinds.OuterSelectName(name.toTermName, levels)) + def unapply(x: SelectOuter): (Term, String, Int) = + (x.qualifier, x.name.toString, x.level) + end SelectOuter + + given SelectOuterMethods: SelectOuterMethods with + extension (self: SelectOuter) + def qualifier: Term = self.qualifier + def name: String = self.name.toString + def level: Int = + val NameKinds.OuterSelectName(_, levels) = self.name + levels + end extension + end SelectOuterMethods + + type While = tpd.WhileDo + + object WhileTypeTest extends TypeTest[Tree, While]: + def unapply(x: Tree): Option[While & x.type] = x match + case x: (tpd.WhileDo & x.type) => Some(x) + case _ => None + end WhileTypeTest + + object While extends WhileModule: + def apply(cond: Term, body: Term): While = + withDefaultPos(tpd.WhileDo(cond, body)) + def copy(original: Tree)(cond: Term, body: Term): While = + tpd.cpy.WhileDo(original)(cond, body) + def unapply(x: While): (Term, Term) = + (x.cond, x.body) + end While + + given WhileMethods: WhileMethods with + extension (self: While) + def cond: Term = self.cond + def body: Term = self.body + end extension + end WhileMethods + + type TypeTree = tpd.Tree + + object TypeTreeTypeTest extends TypeTest[Tree, TypeTree]: + def unapply(x: Tree): Option[TypeTree & x.type] = x match + case x: (tpd.TypeBoundsTree & x.type) => None + case x: (tpd.Tree & x.type) if x.isType => Some(x) + case _ => None + end TypeTreeTypeTest + + object TypeTree extends TypeTreeModule: + def of[T <: AnyKind](using tp: scala.quoted.Type[T]): TypeTree = + tp.asInstanceOf[TypeImpl].typeTree + end TypeTree + + given TypeTreeMethods: TypeTreeMethods with + extension (self: TypeTree) + def tpe: TypeRepr = self.tpe.stripTypeVar + end extension + end TypeTreeMethods + + type Inferred = tpd.TypeTree + + object InferredTypeTest extends TypeTest[Tree, Inferred]: + def unapply(x: Tree): Option[Inferred & x.type] = x match + case tpt: (tpd.TypeTree & x.type) if !tpt.tpe.isInstanceOf[Types.TypeBounds] => Some(tpt) + case _ => None + end InferredTypeTest + + object Inferred extends InferredModule: + def apply(tpe: TypeRepr): Inferred = + withDefaultPos(tpd.TypeTree(tpe)) + def unapply(x: Inferred): true = true + end Inferred + + type TypeIdent = tpd.Ident + + object TypeIdentTypeTest extends TypeTest[Tree, TypeIdent]: + def unapply(x: Tree): Option[TypeIdent & x.type] = x match + case tpt: (tpd.Ident & x.type) if tpt.isType => Some(tpt) + case _ => None + end TypeIdentTypeTest + + object TypeIdent extends TypeIdentModule: + def apply(sym: Symbol): TypeTree = + assert(sym.isType) + withDefaultPos(tpd.ref(sym).asInstanceOf[tpd.TypeTree]) + def copy(original: Tree)(name: String): TypeIdent = + tpd.cpy.Ident(original)(name.toTypeName) + def unapply(x: TypeIdent): Some[String] = + Some(x.name.toString) + end TypeIdent + + given TypeIdentMethods: TypeIdentMethods with + extension (self: TypeIdent) + def name: String = self.name.toString + end extension + end TypeIdentMethods + + type TypeSelect = tpd.Select + + object TypeSelectTypeTest extends TypeTest[Tree, TypeSelect]: + def unapply(x: Tree): Option[TypeSelect & x.type] = x match + case tpt: (tpd.Select & x.type) if tpt.isType && tpt.qualifier.isTerm => Some(tpt) + case _ => None + end TypeSelectTypeTest + + object TypeSelect extends TypeSelectModule: + def apply(qualifier: Term, name: String): TypeSelect = + withDefaultPos(tpd.Select(qualifier, name.toTypeName)) + def copy(original: Tree)(qualifier: Term, name: String): TypeSelect = + tpd.cpy.Select(original)(qualifier, name.toTypeName) + def unapply(x: TypeSelect): (Term, String) = + (x.qualifier, x.name.toString) + end TypeSelect + + given TypeSelectMethods: TypeSelectMethods with + extension (self: TypeSelect) + def qualifier: Term = self.qualifier + def name: String = self.name.toString + end extension + end TypeSelectMethods + + type TypeProjection = tpd.Select + + object TypeProjectionTypeTest extends TypeTest[Tree, TypeProjection]: + def unapply(x: Tree): Option[TypeProjection & x.type] = x match + case tpt: (tpd.Select & x.type) if tpt.isType && tpt.qualifier.isType => Some(tpt) + case _ => None + end TypeProjectionTypeTest + + object TypeProjection extends TypeProjectionModule: + def copy(original: Tree)(qualifier: TypeTree, name: String): TypeProjection = + tpd.cpy.Select(original)(qualifier, name.toTypeName) + def unapply(x: TypeProjection): (TypeTree, String) = + (x.qualifier, x.name.toString) + end TypeProjection + + given TypeProjectionMethods: TypeProjectionMethods with + extension (self: TypeProjection) + def qualifier: TypeTree = self.qualifier + def name: String = self.name.toString + end extension + end TypeProjectionMethods + + type Singleton = tpd.SingletonTypeTree + + object SingletonTypeTest extends TypeTest[Tree, Singleton]: + def unapply(x: Tree): Option[Singleton & x.type] = x match + case tpt: (tpd.SingletonTypeTree & x.type) => Some(tpt) + case _ => None + end SingletonTypeTest + + object Singleton extends SingletonModule: + def apply(ref: Term): Singleton = + withDefaultPos(tpd.SingletonTypeTree(ref)) + def copy(original: Tree)(ref: Term): Singleton = + tpd.cpy.SingletonTypeTree(original)(ref) + def unapply(x: Singleton): Some[Term] = + Some(x.ref) + end Singleton + + given SingletonMethods: SingletonMethods with + extension (self: Singleton) + def ref: Term = self.ref + end extension + end SingletonMethods + + type Refined = tpd.RefinedTypeTree + + object RefinedTypeTest extends TypeTest[Tree, Refined]: + def unapply(x: Tree): Option[Refined & x.type] = x match + case tpt: (tpd.RefinedTypeTree & x.type) => Some(tpt) + case _ => None + end RefinedTypeTest + + object Refined extends RefinedModule: + def copy(original: Tree)(tpt: TypeTree, refinements: List[Definition]): Refined = + tpd.cpy.RefinedTypeTree(original)(tpt, refinements) + def unapply(x: Refined): (TypeTree, List[Definition]) = + (x.tpt, x.refinements.asInstanceOf[List[Definition]]) + end Refined + + given RefinedMethods: RefinedMethods with + extension (self: Refined) + def tpt: TypeTree = self.tpt + def refinements: List[Definition] = self.refinements.asInstanceOf[List[Definition]] + end extension + end RefinedMethods + + type Applied = tpd.AppliedTypeTree + + object AppliedTypeTest extends TypeTest[Tree, Applied]: + def unapply(x: Tree): Option[Applied & x.type] = x match + case tpt: (tpd.AppliedTypeTree & x.type) => Some(tpt) + case _ => None + end AppliedTypeTest + + object Applied extends AppliedModule: + def apply(tpt: TypeTree, args: List[Tree]): Applied = + withDefaultPos(tpd.AppliedTypeTree(tpt, args)) + def copy(original: Tree)(tpt: TypeTree, args: List[Tree]): Applied = + tpd.cpy.AppliedTypeTree(original)(tpt, args) + def unapply(x: Applied): (TypeTree, List[Tree /*TypeTree | TypeBoundsTree*/]) = + (x.tpt, x.args) + end Applied + + given AppliedMethods: AppliedMethods with + extension (self: Applied) + def tpt: TypeTree = self.tpt + def args: List[Tree] = self.args + end extension + end AppliedMethods + + type Annotated = tpd.Annotated + + object AnnotatedTypeTest extends TypeTest[Tree, Annotated]: + def unapply(x: Tree): Option[Annotated & x.type] = x match + case tpt: (tpd.Annotated & x.type) => Some(tpt) + case _ => None + end AnnotatedTypeTest + + object Annotated extends AnnotatedModule: + def apply(arg: TypeTree, annotation: Term): Annotated = + withDefaultPos(tpd.Annotated(arg, annotation)) + def copy(original: Tree)(arg: TypeTree, annotation: Term): Annotated = + tpd.cpy.Annotated(original)(arg, annotation) + def unapply(x: Annotated): (TypeTree, Term) = + (x.arg, x.annotation) + end Annotated + + given AnnotatedMethods: AnnotatedMethods with + extension (self: Annotated) + def arg: TypeTree = self.arg + def annotation: Term = self.annot + end extension + end AnnotatedMethods + + type MatchTypeTree = tpd.MatchTypeTree + + object MatchTypeTreeTypeTest extends TypeTest[Tree, MatchTypeTree]: + def unapply(x: Tree): Option[MatchTypeTree & x.type] = x match + case tpt: (tpd.MatchTypeTree & x.type) => Some(tpt) + case _ => None + end MatchTypeTreeTypeTest + + object MatchTypeTree extends MatchTypeTreeModule: + def apply(bound: Option[TypeTree], selector: TypeTree, cases: List[TypeCaseDef]): MatchTypeTree = + withDefaultPos(tpd.MatchTypeTree(bound.getOrElse(tpd.EmptyTree), selector, cases)) + def copy(original: Tree)(bound: Option[TypeTree], selector: TypeTree, cases: List[TypeCaseDef]): MatchTypeTree = + tpd.cpy.MatchTypeTree(original)(bound.getOrElse(tpd.EmptyTree), selector, cases) + def unapply(x: MatchTypeTree): (Option[TypeTree], TypeTree, List[TypeCaseDef]) = + (optional(x.bound), x.selector, x.cases) + end MatchTypeTree + + given MatchTypeTreeMethods: MatchTypeTreeMethods with + extension (self: MatchTypeTree) + def bound: Option[TypeTree] = optional(self.bound) + def selector: TypeTree = self.selector + def cases: List[TypeCaseDef] = self.cases + end extension + end MatchTypeTreeMethods + + type ByName = tpd.ByNameTypeTree + + object ByNameTypeTest extends TypeTest[Tree, ByName]: + def unapply(x: Tree): Option[ByName & x.type] = x match + case tpt: (tpd.ByNameTypeTree & x.type) => Some(tpt) + case _ => None + end ByNameTypeTest + + object ByName extends ByNameModule: + def apply(result: TypeTree): ByName = + withDefaultPos(tpd.ByNameTypeTree(result)) + def copy(original: Tree)(result: TypeTree): ByName = + tpd.cpy.ByNameTypeTree(original)(result) + def unapply(x: ByName): Some[TypeTree] = + Some(x.result) + end ByName + + given ByNameMethods: ByNameMethods with + extension (self: ByName) + def result: TypeTree = self.result + end extension + end ByNameMethods + + type LambdaTypeTree = tpd.LambdaTypeTree + + object LambdaTypeTreeTypeTest extends TypeTest[Tree, LambdaTypeTree]: + def unapply(x: Tree): Option[LambdaTypeTree & x.type] = x match + case tpt: (tpd.LambdaTypeTree & x.type) => Some(tpt) + case _ => None + end LambdaTypeTreeTypeTest + + object LambdaTypeTree extends LambdaTypeTreeModule: + def apply(tparams: List[TypeDef], body: Tree): LambdaTypeTree = + withDefaultPos(tpd.LambdaTypeTree(tparams, body)) + def copy(original: Tree)(tparams: List[TypeDef], body: Tree): LambdaTypeTree = + tpd.cpy.LambdaTypeTree(original)(tparams, body) + def unapply(tree: LambdaTypeTree): (List[TypeDef], Tree /*TypeTree | TypeBoundsTree*/) = + (tree.tparams, tree.body) + end LambdaTypeTree + + given LambdaTypeTreeMethods: LambdaTypeTreeMethods with + extension (self: LambdaTypeTree) + def tparams: List[TypeDef] = self.tparams + def body: Tree = self.body + end extension + end LambdaTypeTreeMethods + + type TypeBind = tpd.Bind + + object TypeBindTypeTest extends TypeTest[Tree, TypeBind]: + def unapply(x: Tree): Option[TypeBind & x.type] = x match + case tpt: (tpd.Bind & x.type) if tpt.name.isTypeName => Some(tpt) + case _ => None + end TypeBindTypeTest + + object TypeBind extends TypeBindModule: + def copy(original: Tree)(name: String, tpt: Tree): TypeBind = + tpd.cpy.Bind(original)(name.toTypeName, tpt) + def unapply(x: TypeBind): (String, Tree /*TypeTree | TypeBoundsTree*/) = + (x.name.toString, x.body) + end TypeBind + + given TypeBindMethods: TypeBindMethods with + extension (self: TypeBind) + def name: String = self.name.toString + def body: Tree = self.body + end extension + end TypeBindMethods + + type TypeBlock = tpd.Block + + object TypeBlockTypeTest extends TypeTest[Tree, TypeBlock]: + def unapply(x: Tree): Option[TypeBlock & x.type] = x match + case tpt: (tpd.Block & x.type) => Some(tpt) + case _ => None + end TypeBlockTypeTest + + object TypeBlock extends TypeBlockModule: + def apply(aliases: List[TypeDef], tpt: TypeTree): TypeBlock = + withDefaultPos(tpd.Block(aliases, tpt)) + def copy(original: Tree)(aliases: List[TypeDef], tpt: TypeTree): TypeBlock = + tpd.cpy.Block(original)(aliases, tpt) + def unapply(x: TypeBlock): (List[TypeDef], TypeTree) = + (x.aliases, x.tpt) + end TypeBlock + + given TypeBlockMethods: TypeBlockMethods with + extension (self: TypeBlock) + def aliases: List[TypeDef] = self.stats.map { case alias: TypeDef => alias } + def tpt: TypeTree = self.expr + end extension + end TypeBlockMethods + + type TypeBoundsTree = tpd.TypeBoundsTree | tpd.TypeTree + + object TypeBoundsTreeTypeTest extends TypeTest[Tree, TypeBoundsTree]: + def unapply(x: Tree): Option[TypeBoundsTree & x.type] = x match + case x: (tpd.TypeBoundsTree & x.type) => Some(x) + case x: (tpd.TypeTree & x.type) => + x.tpe match + case tpe: Types.TypeBounds => Some(x) + case _ => None + case _ => None + end TypeBoundsTreeTypeTest + + object TypeBoundsTree extends TypeBoundsTreeModule: + def apply(low: TypeTree, hi: TypeTree): TypeBoundsTree = + withDefaultPos(tpd.TypeBoundsTree(low, hi)) + def copy(original: Tree)(low: TypeTree, hi: TypeTree): TypeBoundsTree = + tpd.cpy.TypeBoundsTree(original)(low, hi, tpd.EmptyTree) + def unapply(x: TypeBoundsTree): (TypeTree, TypeTree) = + (x.low, x.hi) + end TypeBoundsTree + + given TypeBoundsTreeMethods: TypeBoundsTreeMethods with + extension (self: TypeBoundsTree) + def tpe: TypeBounds = self.tpe.asInstanceOf[Types.TypeBounds] + def low: TypeTree = self match + case self: tpd.TypeBoundsTree => self.lo + case self: tpd.TypeTree => tpd.TypeTree(self.tpe.asInstanceOf[Types.TypeBounds].lo).withSpan(self.span) + def hi: TypeTree = self match + case self: tpd.TypeBoundsTree => self.hi + case self: tpd.TypeTree => tpd.TypeTree(self.tpe.asInstanceOf[Types.TypeBounds].hi).withSpan(self.span) + end extension + end TypeBoundsTreeMethods + + type WildcardTypeTree = tpd.Ident + + object WildcardTypeTreeTypeTest extends TypeTest[Tree, WildcardTypeTree]: + def unapply(x: Tree): Option[WildcardTypeTree & x.type] = x match + case x: (tpd.Ident & x.type) if x.name == nme.WILDCARD => Some(x) + case _ => None + end WildcardTypeTreeTypeTest + + object WildcardTypeTree extends WildcardTypeTreeModule: + def apply(tpe: TypeRepr): WildcardTypeTree = withDefaultPos(tpd.Underscore(tpe)) + def unapply(x: WildcardTypeTree): true = true + end WildcardTypeTree + + given WildcardTypeTreeMethods: WildcardTypeTreeMethods with + extension (self: WildcardTypeTree) + def tpe: TypeRepr = self.tpe.stripTypeVar + end extension + end WildcardTypeTreeMethods + + type CaseDef = tpd.CaseDef + + object CaseDefTypeTest extends TypeTest[Tree, CaseDef]: + def unapply(x: Tree): Option[CaseDef & x.type] = x match + case tree: (tpd.CaseDef & x.type) if tree.body.isTerm => Some(tree) + case _ => None + end CaseDefTypeTest + + object CaseDef extends CaseDefModule: + def apply(pattern: Tree, guard: Option[Term], rhs: Term): CaseDef = + tpd.CaseDef(pattern, guard.getOrElse(tpd.EmptyTree), rhs) + def copy(original: Tree)(pattern: Tree, guard: Option[Term], rhs: Term): CaseDef = + tpd.cpy.CaseDef(original)(pattern, guard.getOrElse(tpd.EmptyTree), rhs) + def unapply(x: CaseDef): (Tree, Option[Term], Term) = + (x.pat, optional(x.guard), x.body) + end CaseDef + + given CaseDefMethods: CaseDefMethods with + extension (self: CaseDef) + def pattern: Tree = self.pat + def guard: Option[Term] = optional(self.guard) + def rhs: Term = self.body + end extension + end CaseDefMethods + + type TypeCaseDef = tpd.CaseDef + + object TypeCaseDefTypeTest extends TypeTest[Tree, TypeCaseDef]: + def unapply(x: Tree): Option[TypeCaseDef & x.type] = x match + case tree: (tpd.CaseDef & x.type) if tree.body.isType => Some(tree) + case _ => None + end TypeCaseDefTypeTest + + object TypeCaseDef extends TypeCaseDefModule: + def apply(pattern: TypeTree, rhs: TypeTree): TypeCaseDef = + tpd.CaseDef(pattern, tpd.EmptyTree, rhs) + def copy(original: Tree)(pattern: TypeTree, rhs: TypeTree): TypeCaseDef = + tpd.cpy.CaseDef(original)(pattern, tpd.EmptyTree, rhs) + def unapply(tree: TypeCaseDef): (TypeTree, TypeTree) = + (tree.pat, tree.body) + end TypeCaseDef + + given TypeCaseDefMethods: TypeCaseDefMethods with + extension (self: TypeCaseDef) + def pattern: TypeTree = self.pat + def rhs: TypeTree = self.body + end extension + end TypeCaseDefMethods + + type Bind = tpd.Bind + + object BindTypeTest extends TypeTest[Tree, Bind]: + def unapply(x: Tree): Option[Bind & x.type] = x match + case x: (tpd.Bind & x.type) if x.name.isTermName => Some(x) + case _ => None + end BindTypeTest + + object Bind extends BindModule: + def apply(sym: Symbol, pattern: Tree): Bind = + tpd.Bind(sym, pattern) + def copy(original: Tree)(name: String, pattern: Tree): Bind = + withDefaultPos(tpd.cpy.Bind(original)(name.toTermName, pattern)) + def unapply(pattern: Bind): (String, Tree) = + (pattern.name.toString, pattern.pattern) + end Bind + + given BindMethods: BindMethods with + extension (self: Bind) + def name: String = self.name.toString + def pattern: Tree = self.body + end extension + end BindMethods + + type Unapply = tpd.UnApply | tpd.Typed // tpd.Typed containing a tpd.UnApply as expression + + object UnapplyTypeTest extends TypeTest[Tree, Unapply]: + def unapply(x: Tree): Option[Unapply & x.type] = + x match // keep in sync with UnapplyMethodsImpl.selfUnApply + case x: (tpd.UnApply & x.type) => Some(x) + case x: (tpd.Typed & x.type) if x.expr.isInstanceOf[tpd.UnApply] => Some(x) + case _ => None + end UnapplyTypeTest + + object Unapply extends UnapplyModule: + def copy(original: Tree)(fun: Term, implicits: List[Term], patterns: List[Tree]): Unapply = + withDefaultPos(tpd.cpy.UnApply(original)(fun, implicits, patterns)) + def unapply(x: Unapply): (Term, List[Term], List[Tree]) = + (x.fun, x.implicits, x.patterns) + end Unapply + + given UnapplyMethods: UnapplyMethods with + extension (self: Unapply) + def fun: Term = selfUnApply(self).fun + def implicits: List[Term] = selfUnApply(self).implicits + def patterns: List[Tree] = effectivePatterns(selfUnApply(self).patterns) + end extension + private def selfUnApply(self: Unapply): tpd.UnApply = + self match // keep in sync with UnapplyTypeTest + case self: tpd.UnApply => self + case self: tpd.Typed => self.expr.asInstanceOf[tpd.UnApply] + private def effectivePatterns(patterns: List[Tree]): List[Tree] = + patterns match + case patterns0 :+ dotc.ast.Trees.SeqLiteral(elems, _) => patterns0 ::: elems + case _ => patterns + end UnapplyMethods + + type Alternatives = tpd.Alternative + + object AlternativesTypeTest extends TypeTest[Tree, Alternatives]: + def unapply(x: Tree): Option[Alternatives & x.type] = x match + case x: (tpd.Alternative & x.type) => Some(x) + case _ => None + end AlternativesTypeTest + + object Alternatives extends AlternativesModule: + def apply(patterns: List[Tree]): Alternatives = + withDefaultPos(tpd.Alternative(patterns)) + def copy(original: Tree)(patterns: List[Tree]): Alternatives = + tpd.cpy.Alternative(original)(patterns) + def unapply(x: Alternatives): Some[List[Tree]] = + Some(x.patterns) + end Alternatives + + given AlternativesMethods: AlternativesMethods with + extension (self: Alternatives) + def patterns: List[Tree] = self.trees + end extension + end AlternativesMethods + + type Selector = untpd.ImportSelector + + object Selector extends SelectorModule + + type SimpleSelector = untpd.ImportSelector + + object SimpleSelectorTypeTest extends TypeTest[Selector, SimpleSelector]: + def unapply(x: Selector): Option[SimpleSelector & x.type] = x match + case x: (untpd.ImportSelector & x.type) if x.renamed.isEmpty && !x.isGiven => Some(x) + case _ => None // TODO: handle import bounds + end SimpleSelectorTypeTest + + object SimpleSelector extends SimpleSelectorModule: + def unapply(x: SimpleSelector): Some[String] = Some(x.name.toString) + end SimpleSelector + + given SimpleSelectorMethods: SimpleSelectorMethods with + extension (self: SimpleSelector) + def name: String = self.imported.name.toString + def namePos: Position = self.imported.sourcePos + end extension + end SimpleSelectorMethods + + type RenameSelector = untpd.ImportSelector + + object RenameSelectorTypeTest extends TypeTest[Selector, RenameSelector]: + def unapply(x: Selector): Option[RenameSelector & x.type] = x match + case x: (untpd.ImportSelector & x.type) if !x.renamed.isEmpty => Some(x) + case _ => None + end RenameSelectorTypeTest + + object RenameSelector extends RenameSelectorModule: + def unapply(x: RenameSelector): (String, String) = (x.fromName, x.toName) + end RenameSelector + + given RenameSelectorMethods: RenameSelectorMethods with + extension (self: RenameSelector) + def fromName: String = self.imported.name.toString + def fromPos: Position = self.imported.sourcePos + def toName: String = self.renamed.asInstanceOf[untpd.Ident].name.toString + def toPos: Position = self.renamed.asInstanceOf[untpd.Ident].sourcePos + end extension + end RenameSelectorMethods + + type OmitSelector = untpd.ImportSelector + + object OmitSelectorTypeTest extends TypeTest[Selector, OmitSelector]: + def unapply(x: Selector): Option[OmitSelector & x.type] = x match { + case self: (untpd.ImportSelector & x.type) => + self.renamed match + case dotc.ast.Trees.Ident(nme.WILDCARD) => Some(self) + case _ => None + case _ => None + } + end OmitSelectorTypeTest + + object OmitSelector extends OmitSelectorModule: + def unapply(x: OmitSelector): Some[String] = Some(x.imported.name.toString) + end OmitSelector + + given OmitSelectorMethods: OmitSelectorMethods with + extension (self: OmitSelector) + def name: String = self.imported.toString + def namePos: Position = self.imported.sourcePos + end extension + end OmitSelectorMethods + + type GivenSelector = untpd.ImportSelector + + object GivenSelectorTypeTest extends TypeTest[Selector, GivenSelector]: + def unapply(x: Selector): Option[GivenSelector & x.type] = x match { + case self: (untpd.ImportSelector & x.type) if x.isGiven => Some(self) + case _ => None + } + end GivenSelectorTypeTest + + object GivenSelector extends GivenSelectorModule: + def unapply(x: GivenSelector): Some[Option[TypeTree]] = + Some(GivenSelectorMethods.bound(x)) + end GivenSelector + + given GivenSelectorMethods: GivenSelectorMethods with + extension (self: GivenSelector) + def bound: Option[TypeTree] = + self.bound match + case untpd.TypedSplice(tpt) => Some(tpt) + case _ => None + end extension + end GivenSelectorMethods + + type TypeRepr = dotc.core.Types.Type + + object TypeRepr extends TypeReprModule: + def of[T <: AnyKind](using tp: scala.quoted.Type[T]): TypeRepr = + tp.asInstanceOf[TypeImpl].typeTree.tpe + def typeConstructorOf(clazz: Class[?]): TypeRepr = + if (clazz.isPrimitive) + if (clazz == classOf[Boolean]) dotc.core.Symbols.defn.BooleanType + else if (clazz == classOf[Byte]) dotc.core.Symbols.defn.ByteType + else if (clazz == classOf[Char]) dotc.core.Symbols.defn.CharType + else if (clazz == classOf[Short]) dotc.core.Symbols.defn.ShortType + else if (clazz == classOf[Int]) dotc.core.Symbols.defn.IntType + else if (clazz == classOf[Long]) dotc.core.Symbols.defn.LongType + else if (clazz == classOf[Float]) dotc.core.Symbols.defn.FloatType + else if (clazz == classOf[Double]) dotc.core.Symbols.defn.DoubleType + else dotc.core.Symbols.defn.UnitType + else if (clazz.isArray) + dotc.core.Symbols.defn.ArrayType.appliedTo(typeConstructorOf(clazz.getComponentType)) + else if clazz.isMemberClass then + val name = clazz.getSimpleName.toTypeName + val enclosing = typeConstructorOf(clazz.getEnclosingClass) + if (enclosing.member(name).exists) enclosing.select(name) + else enclosing.classSymbol.companionModule.termRef.select(name) + else + dotc.core.Symbols.getClassIfDefined(clazz.getCanonicalName).typeRef + end TypeRepr + + given TypeReprMethods: TypeReprMethods with + extension (self: TypeRepr) + + def show(using printer: Printer[TypeRepr]): String = printer.show(self) + + def seal: scala.quoted.Type[_] = self.asType + + def asType: scala.quoted.Type[?] = + new TypeImpl(Inferred(self), QuotesImpl.this.hashCode) + + def =:=(that: TypeRepr): Boolean = self =:= that + def <:<(that: TypeRepr): Boolean = self <:< that + def widen: TypeRepr = self.widen + def widenTermRefExpr: TypeRepr = self.widenTermRefExpr + def dealias: TypeRepr = self.dealias + def simplified: TypeRepr = self.simplified + def classSymbol: Option[Symbol] = + if self.classSymbol.exists then Some(self.classSymbol.asClass) + else None + def typeSymbol: Symbol = self.typeSymbol + def termSymbol: Symbol = self.termSymbol + def isSingleton: Boolean = self.isSingleton + def memberType(member: Symbol): TypeRepr = + member.info.asSeenFrom(self, member.owner) + def baseClasses: List[Symbol] = self.baseClasses + 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) + def isContextFunctionType: Boolean = + dotc.core.Symbols.defn.isContextFunctionType(self) + def isErasedFunctionType: Boolean = + dotc.core.Symbols.defn.isErasedFunctionType(self) + def isDependentFunctionType: Boolean = + val tpNoRefinement = self.dropDependentRefinement + tpNoRefinement != self + && dotc.core.Symbols.defn.isNonRefinedFunction(tpNoRefinement) + def select(sym: Symbol): TypeRepr = self.select(sym) + def appliedTo(targ: TypeRepr): TypeRepr = + dotc.core.Types.decorateTypeApplications(self).appliedTo(targ) + def appliedTo(targs: List[TypeRepr]): TypeRepr = + dotc.core.Types.decorateTypeApplications(self).appliedTo(targs) + end extension + end TypeReprMethods + + type ConstantType = dotc.core.Types.ConstantType + + object ConstantTypeTypeTest extends TypeTest[TypeRepr, ConstantType]: + def unapply(x: TypeRepr): Option[ConstantType & x.type] = x match + case tpe: (Types.ConstantType & x.type) => Some(tpe) + case _ => None + end ConstantTypeTypeTest + + object ConstantType extends ConstantTypeModule: + def apply(const: Constant): ConstantType = Types.ConstantType(const) + def unapply(x: ConstantType): Some[Constant] = Some(x.constant) + end ConstantType + + given ConstantTypeMethods: ConstantTypeMethods with + extension (self: ConstantType) def constant: Constant = self.value + end ConstantTypeMethods + + type NamedType = dotc.core.Types.NamedType + + object NamedTypeTypeTest extends TypeTest[TypeRepr, NamedType]: + def unapply(x: TypeRepr): Option[NamedType & x.type] = x match + case tpe: (Types.NamedType & x.type) => Some(tpe) + case _ => None + end NamedTypeTypeTest + + given NamedTypeMethods: NamedTypeMethods with + extension (self: NamedType) + def qualifier: TypeRepr = self.prefix + def name: String = self.name.toString + end extension + end NamedTypeMethods + + type TermRef = dotc.core.Types.NamedType + + object TermRefTypeTest extends TypeTest[TypeRepr, TermRef]: + def unapply(x: TypeRepr): Option[TermRef & x.type] = x match + case tpe: (Types.TermRef & x.type) => Some(tpe) + case _ => None + end TermRefTypeTest + + object TermRef extends TermRefModule: + def apply(qual: TypeRepr, name: String): TermRef = + Types.TermRef(qual, name.toTermName) + def unapply(x: TermRef): (TypeRepr, String) = + (x.prefix, x.name.toString) + end TermRef + + type TypeRef = dotc.core.Types.NamedType + + object TypeRefTypeTest extends TypeTest[TypeRepr, TypeRef]: + def unapply(x: TypeRepr): Option[TypeRef & x.type] = x match + case tpe: (Types.TypeRef & x.type) => Some(tpe) + case _ => None + end TypeRefTypeTest + + object TypeRef extends TypeRefModule: + def unapply(x: TypeRef): (TypeRepr, String) = + (x.prefix, x.name.toString) + end TypeRef + + given TypeRefMethods: TypeRefMethods with + extension (self: TypeRef) + def isOpaqueAlias: Boolean = self.symbol.isOpaqueAlias + def translucentSuperType: TypeRepr = self.translucentSuperType + end extension + end TypeRefMethods + + type SuperType = dotc.core.Types.SuperType + + object SuperTypeTypeTest extends TypeTest[TypeRepr, SuperType]: + def unapply(x: TypeRepr): Option[SuperType & x.type] = x match + case tpe: (Types.SuperType & x.type) => Some(tpe) + case _ => None + end SuperTypeTypeTest + + object SuperType extends SuperTypeModule: + def apply(thistpe: TypeRepr, supertpe: TypeRepr): SuperType = + Types.SuperType(thistpe, supertpe) + def unapply(x: SuperType): (TypeRepr, TypeRepr) = + (x.thistpe, x.supertpe) + end SuperType + + given SuperTypeMethods: SuperTypeMethods with + extension (self: SuperType) + def thistpe: TypeRepr = self.thistpe + def supertpe: TypeRepr = self.thistpe + end extension + end SuperTypeMethods + + type Refinement = dotc.core.Types.RefinedType + + object RefinementTypeTest extends TypeTest[TypeRepr, Refinement]: + def unapply(x: TypeRepr): Option[Refinement & x.type] = x match + case tpe: (Types.RefinedType & x.type) => Some(tpe) + case _ => None + end RefinementTypeTest + + object Refinement extends RefinementModule: + def apply(parent: TypeRepr, name: String, info: TypeRepr): Refinement = + val name1 = + info match + case _: TypeBounds => name.toTypeName + case _ => name.toTermName + Types.RefinedType(parent, name1, info) + def unapply(x: Refinement): (TypeRepr, String, TypeRepr) = + (x.parent, x.name, x.info) + end Refinement + + given RefinementMethods: RefinementMethods with + extension (self: Refinement) + def parent: TypeRepr = self.parent + def name: String = self.refinedName.toString + def info: TypeRepr = self.refinedInfo + end extension + end RefinementMethods + + type AppliedType = dotc.core.Types.AppliedType + + object AppliedTypeTypeTest extends TypeTest[TypeRepr, AppliedType]: + def unapply(x: TypeRepr): Option[AppliedType & x.type] = x match + case tpe: (Types.AppliedType & x.type) if !tpe.tycon.isRef(dotc.core.Symbols.defn.MatchCaseClass) => Some(tpe) + case _ => None + end AppliedTypeTypeTest + + object AppliedType extends AppliedTypeModule: + def unapply(x: AppliedType): (TypeRepr, List[TypeRepr]) = + (x.tycon, x.args) + end AppliedType + + given AppliedTypeMethods: AppliedTypeMethods with + extension (self: AppliedType) + def tycon: TypeRepr = self.tycon + def args: List[TypeRepr] = self.args + end extension + end AppliedTypeMethods + + type AnnotatedType = dotc.core.Types.AnnotatedType + + object AnnotatedTypeTypeTest extends TypeTest[TypeRepr, AnnotatedType]: + def unapply(x: TypeRepr): Option[AnnotatedType & x.type] = x match + case tpe: (Types.AnnotatedType & x.type) => Some(tpe) + case _ => None + end AnnotatedTypeTypeTest + + object AnnotatedType extends AnnotatedTypeModule: + def apply(underlying: TypeRepr, annot: Term): AnnotatedType = + Types.AnnotatedType(underlying, Annotations.Annotation(annot)) + def unapply(x: AnnotatedType): (TypeRepr, Term) = + (x.underlying.stripTypeVar, x.annot.tree) + end AnnotatedType + + given AnnotatedTypeMethods: AnnotatedTypeMethods with + extension (self: AnnotatedType) + def underlying: TypeRepr = self.underlying.stripTypeVar + def annotation: Term = self.annot.tree + end extension + end AnnotatedTypeMethods + + type AndOrType = dotc.core.Types.AndOrType + + object AndOrTypeTypeTest extends TypeTest[TypeRepr, AndOrType]: + def unapply(x: TypeRepr): Option[AndOrType & x.type] = x match + case tpe: (Types.AndOrType & x.type) => Some(tpe) + case _ => None + end AndOrTypeTypeTest + + given AndOrTypeMethods: AndOrTypeMethods with + extension (self: AndOrType) + def left: TypeRepr = self.tp1.stripTypeVar + def right: TypeRepr = self.tp2.stripTypeVar + end extension + end AndOrTypeMethods + + type AndType = dotc.core.Types.AndType + + object AndTypeTypeTest extends TypeTest[TypeRepr, AndType]: + def unapply(x: TypeRepr): Option[AndType & x.type] = x match + case tpe: (Types.AndType & x.type) => Some(tpe) + case _ => None + end AndTypeTypeTest + + object AndType extends AndTypeModule: + def apply(lhs: TypeRepr, rhs: TypeRepr): AndType = Types.AndType(lhs, rhs) + def unapply(x: AndType): (TypeRepr, TypeRepr) = (x.left, x.right) + end AndType + + type OrType = dotc.core.Types.OrType + + object OrTypeTypeTest extends TypeTest[TypeRepr, OrType]: + def unapply(x: TypeRepr): Option[OrType & x.type] = x match + case tpe: (Types.OrType & x.type) => Some(tpe) + case _ => None + end OrTypeTypeTest + + object OrType extends OrTypeModule: + def apply(lhs: TypeRepr, rhs: TypeRepr): OrType = Types.OrType(lhs, rhs, soft = false) + def unapply(x: OrType): (TypeRepr, TypeRepr) = (x.left, x.right) + end OrType + + type MatchType = dotc.core.Types.MatchType + + object MatchTypeTypeTest extends TypeTest[TypeRepr, MatchType]: + def unapply(x: TypeRepr): Option[MatchType & x.type] = x match + case tpe: (Types.MatchType & x.type) => Some(tpe) + case _ => None + end MatchTypeTypeTest + + object MatchType extends MatchTypeModule: + def apply(bound: TypeRepr, scrutinee: TypeRepr, cases: List[TypeRepr]): MatchType = + Types.MatchType(bound, scrutinee, cases) + def unapply(x: MatchType): (TypeRepr, TypeRepr, List[TypeRepr]) = + (x.bound, x.scrutinee, x.cases) + end MatchType + + given MatchTypeMethods: MatchTypeMethods with + extension (self: MatchType) + def bound: TypeRepr = self.bound + def scrutinee: TypeRepr = self.scrutinee + def cases: List[TypeRepr] = self.cases + end extension + end MatchTypeMethods + + type ByNameType = dotc.core.Types.ExprType + + object ByNameTypeTypeTest extends TypeTest[TypeRepr, ByNameType]: + def unapply(x: TypeRepr): Option[ByNameType & x.type] = x match + case tpe: (Types.ExprType & x.type) => Some(tpe) + case _ => None + end ByNameTypeTypeTest + + object ByNameType extends ByNameTypeModule: + def apply(underlying: TypeRepr): TypeRepr = Types.ExprType(underlying) + def unapply(x: ByNameType): Some[TypeRepr] = Some(x.underlying) + end ByNameType + + given ByNameTypeMethods: ByNameTypeMethods with + extension (self: ByNameType) + def underlying: TypeRepr = self.resType.stripTypeVar + end extension + end ByNameTypeMethods + + type ParamRef = dotc.core.Types.ParamRef + + object ParamRefTypeTest extends TypeTest[TypeRepr, ParamRef]: + def unapply(x: TypeRepr): Option[ParamRef & x.type] = x match + case tpe: (Types.TypeParamRef & x.type) => Some(tpe) + case tpe: (Types.TermParamRef & x.type) => Some(tpe) + case _ => None + end ParamRefTypeTest + + object ParamRef extends ParamRefModule: + def unapply(x: ParamRef): (LambdaType, Int) = + (x.binder, x.paramNum) + end ParamRef + + given ParamRefMethods: ParamRefMethods with + extension (self: ParamRef) + def binder: LambdaType = self.binder.asInstanceOf[LambdaType] // Cast to tpd + def paramNum: Int = self.paramNum + end extension + end ParamRefMethods + + type ThisType = dotc.core.Types.ThisType + + object ThisTypeTypeTest extends TypeTest[TypeRepr, ThisType]: + def unapply(x: TypeRepr): Option[ThisType & x.type] = x match + case tpe: (Types.ThisType & x.type) => Some(tpe) + case _ => None + end ThisTypeTypeTest + + object ThisType extends ThisTypeModule: + def unapply(x: ThisType): Some[TypeRepr] = Some(x.tref) + end ThisType + + given ThisTypeMethods: ThisTypeMethods with + extension (self: ThisType) + def tref: TypeRepr = self.tref + end extension + end ThisTypeMethods + + type RecursiveThis = dotc.core.Types.RecThis + + object RecursiveThisTypeTest extends TypeTest[TypeRepr, RecursiveThis]: + def unapply(x: TypeRepr): Option[RecursiveThis & x.type] = x match + case tpe: (Types.RecThis & x.type) => Some(tpe) + case _ => None + end RecursiveThisTypeTest + + object RecursiveThis extends RecursiveThisModule: + def unapply(x: RecursiveThis): Some[RecursiveType] = Some(x.binder) + end RecursiveThis + + + given RecursiveThisMethods: RecursiveThisMethods with + extension (self: RecursiveThis) + def binder: RecursiveType = self.binder + end extension + end RecursiveThisMethods + + type RecursiveType = dotc.core.Types.RecType + + object RecursiveTypeTypeTest extends TypeTest[TypeRepr, RecursiveType]: + def unapply(x: TypeRepr): Option[RecursiveType & x.type] = x match + case tpe: (Types.RecType & x.type) => Some(tpe) + case _ => None + end RecursiveTypeTypeTest + + object RecursiveType extends RecursiveTypeModule: + def apply(parentExp: RecursiveType => TypeRepr): RecursiveType = + Types.RecType(parentExp) + def unapply(x: RecursiveType): Some[TypeRepr] = Some(x.underlying) + end RecursiveType + + given RecursiveTypeMethods: RecursiveTypeMethods with + extension (self: RecursiveType) + def underlying: TypeRepr = self.underlying.stripTypeVar + def recThis: RecursiveThis = self.recThis + end extension + end RecursiveTypeMethods + + type LambdaType = dotc.core.Types.LambdaType + + object LambdaTypeTypeTest extends TypeTest[TypeRepr, LambdaType]: + def unapply(x: TypeRepr): Option[LambdaType & x.type] = x match + case tpe: (Types.LambdaType & x.type) => Some(tpe) + case _ => None + end LambdaTypeTypeTest + + given LambdaTypeMethods: LambdaTypeMethods with + extension (self: LambdaType) + def paramNames: List[String] = self.paramNames.map(_.toString) + def paramTypes: List[TypeRepr] = self.paramInfos + def resType: TypeRepr = self.resType + end extension + end LambdaTypeMethods + + type MethodOrPoly = dotc.core.Types.MethodOrPoly + + object MethodOrPolyTypeTest extends TypeTest[TypeRepr, MethodOrPoly]: + def unapply(x: TypeRepr): Option[MethodOrPoly & x.type] = x match + case tpe: (Types.MethodOrPoly & x.type) => Some(tpe) + case _ => None + end MethodOrPolyTypeTest + + type MethodType = dotc.core.Types.MethodType + + object MethodTypeTypeTest extends TypeTest[TypeRepr, MethodType]: + def unapply(x: TypeRepr): Option[MethodType & x.type] = x match + case tpe: (Types.MethodType & x.type) => Some(tpe) + case _ => None + end MethodTypeTypeTest + + object MethodType extends MethodTypeModule: + def apply(paramNames: List[String])(paramInfosExp: MethodType => List[TypeRepr], resultTypeExp: MethodType => TypeRepr): MethodType = + Types.MethodType(paramNames.map(_.toTermName))(paramInfosExp, resultTypeExp) + def unapply(x: MethodType): (List[String], List[TypeRepr], TypeRepr) = + (x.paramNames.map(_.toString), x.paramTypes, x.resType) + end MethodType + + given MethodTypeMethods: MethodTypeMethods with + extension (self: MethodType) + def isErased: Boolean = self.isErasedMethod + def isImplicit: Boolean = self.isImplicitMethod + def param(idx: Int): TypeRepr = self.newParamRef(idx) + end extension + end MethodTypeMethods + + type PolyType = dotc.core.Types.PolyType + + object PolyTypeTypeTest extends TypeTest[TypeRepr, PolyType]: + def unapply(x: TypeRepr): Option[PolyType & x.type] = x match + case tpe: (Types.PolyType & x.type) => Some(tpe) + case _ => None + end PolyTypeTypeTest + + object PolyType extends PolyTypeModule: + def apply(paramNames: List[String])(paramBoundsExp: PolyType => List[TypeBounds], resultTypeExp: PolyType => TypeRepr): PolyType = + Types.PolyType(paramNames.map(_.toTypeName))(paramBoundsExp, resultTypeExp) + def unapply(x: PolyType): (List[String], List[TypeBounds], TypeRepr) = + (x.paramNames.map(_.toString), x.paramBounds, x.resType) + end PolyType + + given PolyTypeMethods: PolyTypeMethods with + extension (self: PolyType) + def param(idx: Int): TypeRepr = self.newParamRef(idx) + def paramBounds: List[TypeBounds] = self.paramInfos + end extension + end PolyTypeMethods + + type TypeLambda = dotc.core.Types.TypeLambda + + object TypeLambdaTypeTest extends TypeTest[TypeRepr, TypeLambda]: + def unapply(x: TypeRepr): Option[TypeLambda & x.type] = x match + case tpe: (Types.TypeLambda & x.type) => Some(tpe) + case _ => None + end TypeLambdaTypeTest + + object TypeLambda extends TypeLambdaModule: + def apply(paramNames: List[String], boundsFn: TypeLambda => List[TypeBounds], bodyFn: TypeLambda => TypeRepr): TypeLambda = + Types.HKTypeLambda(paramNames.map(_.toTypeName))(boundsFn, bodyFn) + def unapply(x: TypeLambda): (List[String], List[TypeBounds], TypeRepr) = + (x.paramNames.map(_.toString), x.paramBounds, x.resType) + end TypeLambda + + given TypeLambdaMethods: TypeLambdaMethods with + extension (self: TypeLambda) + def param(idx: Int): TypeRepr = self.newParamRef(idx) + def paramBounds: List[TypeBounds] = self.paramInfos + end extension + end TypeLambdaMethods + + type MatchCase = dotc.core.Types.AppliedType + + given MatchCaseTypeTest: TypeTest[TypeRepr, MatchCase] with + def unapply(x: TypeRepr): Option[MatchCase & x.type] = x match + case x: (Types.AppliedType & x.type) if x.tycon.isRef(dotc.core.Symbols.defn.MatchCaseClass) => Some(x) + case _ => None + end MatchCaseTypeTest + + object MatchCase extends MatchCaseModule: + def apply(pattern: TypeRepr, rhs: TypeRepr): MatchCase = + Types.AppliedType(dotc.core.Symbols.defn.MatchCaseClass.typeRef, List(pattern, rhs)) + def unapply(x: MatchCase): (TypeRepr, TypeRepr) = (x.pattern, x.rhs) + end MatchCase + + given MatchCaseMethods: MatchCaseMethods with + extension (self: MatchCase) + def pattern: TypeRepr = self.args(0) + def rhs: TypeRepr = self.args(1) + end extension + end MatchCaseMethods + + type TypeBounds = dotc.core.Types.TypeBounds + + object TypeBoundsTypeTest extends TypeTest[TypeRepr, TypeBounds]: + def unapply(x: TypeRepr): Option[TypeBounds & x.type] = x match + case x: (Types.TypeBounds & x.type) => Some(x) + case _ => None + end TypeBoundsTypeTest + + object TypeBounds extends TypeBoundsModule: + def apply(low: TypeRepr, hi: TypeRepr): TypeBounds = Types.TypeBounds(low, hi) + def unapply(x: TypeBounds): (TypeRepr, TypeRepr) = (x.low.stripLazyRef, x.hi.stripLazyRef) + def empty: TypeBounds = Types .TypeBounds.empty + def upper(hi: TypeRepr): TypeBounds = Types .TypeBounds.upper(hi) + def lower(lo: TypeRepr): TypeBounds = Types .TypeBounds.lower(lo) + end TypeBounds + + given TypeBoundsMethods: TypeBoundsMethods with + extension (self: TypeBounds) + def low: TypeRepr = self.lo.stripLazyRef + def hi: TypeRepr = self.hi.stripLazyRef + end extension + end TypeBoundsMethods + + type NoPrefix = dotc.core.Types.NoPrefix.type + + object NoPrefixTypeTest extends TypeTest[TypeRepr, NoPrefix]: + def unapply(x: TypeRepr): Option[NoPrefix & x.type] = + if x == Types.NoPrefix then Some(x.asInstanceOf[NoPrefix & x.type]) else None + end NoPrefixTypeTest + + object NoPrefix extends NoPrefixModule: + def unapply(x: NoPrefix): true = true + end NoPrefix + + type Constant = dotc.core.Constants.Constant + + object Constant extends ConstantModule + + given ConstantMethods: ConstantMethods with + extension (self: Constant) + def value: Any = self.value + def show(using printer: Printer[Constant]): String = printer.show(self) + end extension + end ConstantMethods + + type BooleanConstant = dotc.core.Constants.Constant + + object BooleanConstantTypeTest extends TypeTest[Constant, BooleanConstant]: + def unapply(x: Constant): Option[BooleanConstant & x.type] = + if x.tag == dotc.core.Constants.BooleanTag then Some(x.asInstanceOf[BooleanConstant & x.type]) else None + end BooleanConstantTypeTest + + object BooleanConstant extends BooleanConstantModule: + def apply(x: Boolean): BooleanConstant = dotc.core.Constants.Constant(x) + def unapply(constant: BooleanConstant): Some[Boolean] = Some(constant.booleanValue) + end BooleanConstant + + type ByteConstant = dotc.core.Constants.Constant + + object ByteConstantTypeTest extends TypeTest[Constant, ByteConstant]: + def unapply(x: Constant): Option[ByteConstant & x.type] = + if x.tag == dotc.core.Constants.ByteTag then Some(x.asInstanceOf[ByteConstant & x.type]) else None + end ByteConstantTypeTest + + object ByteConstant extends ByteConstantModule: + def apply(x: Byte): ByteConstant = dotc.core.Constants.Constant(x) + def unapply(constant: ByteConstant): Some[Byte] = Some(constant.byteValue) + end ByteConstant + + type ShortConstant = dotc.core.Constants.Constant + + object ShortConstantTypeTest extends TypeTest[Constant, ShortConstant]: + def unapply(x: Constant): Option[ShortConstant & x.type] = + if x.tag == dotc.core.Constants.ShortTag then Some(x.asInstanceOf[ShortConstant & x.type]) else None + end ShortConstantTypeTest + + object ShortConstant extends ShortConstantModule: + def apply(x: Short): ShortConstant = dotc.core.Constants.Constant(x) + def unapply(constant: ShortConstant): Some[Short] = Some(constant.shortValue) + end ShortConstant + + type IntConstant = dotc.core.Constants.Constant + + object IntConstantTypeTest extends TypeTest[Constant, IntConstant]: + def unapply(x: Constant): Option[IntConstant & x.type] = + if x.tag == dotc.core.Constants.IntTag then Some(x.asInstanceOf[IntConstant & x.type]) else None + end IntConstantTypeTest + + object IntConstant extends IntConstantModule: + def apply(x: Int): IntConstant = dotc.core.Constants.Constant(x) + def unapply(constant: IntConstant): Some[Int] = Some(constant.intValue) + end IntConstant + + type LongConstant = dotc.core.Constants.Constant + + object LongConstantTypeTest extends TypeTest[Constant, LongConstant]: + def unapply(x: Constant): Option[LongConstant & x.type] = + if x.tag == dotc.core.Constants.LongTag then Some(x.asInstanceOf[LongConstant & x.type]) else None + end LongConstantTypeTest + + object LongConstant extends LongConstantModule: + def apply(x: Long): LongConstant = dotc.core.Constants.Constant(x) + def unapply(constant: LongConstant): Some[Long] = Some(constant.longValue) + end LongConstant + + type FloatConstant = dotc.core.Constants.Constant + + object FloatConstantTypeTest extends TypeTest[Constant, FloatConstant]: + def unapply(x: Constant): Option[FloatConstant & x.type] = + if x.tag == dotc.core.Constants.FloatTag then Some(x.asInstanceOf[FloatConstant & x.type]) else None + end FloatConstantTypeTest + + object FloatConstant extends FloatConstantModule: + def apply(x: Float): FloatConstant = dotc.core.Constants.Constant(x) + def unapply(constant: FloatConstant): Some[Float] = Some(constant.floatValue) + end FloatConstant + + type DoubleConstant = dotc.core.Constants.Constant + + object DoubleConstantTypeTest extends TypeTest[Constant, DoubleConstant]: + def unapply(x: Constant): Option[DoubleConstant & x.type] = + if x.tag == dotc.core.Constants.DoubleTag then Some(x.asInstanceOf[DoubleConstant & x.type]) else None + end DoubleConstantTypeTest + + object DoubleConstant extends DoubleConstantModule: + def apply(x: Double): DoubleConstant = dotc.core.Constants.Constant(x) + def unapply(constant: DoubleConstant): Some[Double] = Some(constant.doubleValue) + end DoubleConstant + + type CharConstant = dotc.core.Constants.Constant + + object CharConstantTypeTest extends TypeTest[Constant, CharConstant]: + def unapply(x: Constant): Option[CharConstant & x.type] = + if x.tag == dotc.core.Constants.CharTag then Some(x.asInstanceOf[CharConstant & x.type]) else None + end CharConstantTypeTest + + object CharConstant extends CharConstantModule: + def apply(x: Char): CharConstant = dotc.core.Constants.Constant(x) + def unapply(constant: CharConstant): Some[Char] = Some(constant.charValue) + end CharConstant + + type StringConstant = dotc.core.Constants.Constant + + object StringConstantTypeTest extends TypeTest[Constant, StringConstant]: + def unapply(x: Constant): Option[StringConstant & x.type] = + if x.tag == dotc.core.Constants.StringTag then Some(x.asInstanceOf[StringConstant & x.type]) else None + end StringConstantTypeTest + + object StringConstant extends StringConstantModule: + def apply(x: String): StringConstant = dotc.core.Constants.Constant(x) + def unapply(constant: StringConstant): Some[String] = Some(constant.stringValue) + end StringConstant + + type UnitConstant = dotc.core.Constants.Constant + + object UnitConstantTypeTest extends TypeTest[Constant, UnitConstant]: + def unapply(x: Constant): Option[UnitConstant & x.type] = + if x.tag == dotc.core.Constants.UnitTag then Some(x.asInstanceOf[UnitConstant & x.type]) else None + end UnitConstantTypeTest + + object UnitConstant extends UnitConstantModule: + def apply(): UnitConstant = dotc.core.Constants.Constant(()) + def unapply(constant: UnitConstant): true = true + end UnitConstant + + type NullConstant = dotc.core.Constants.Constant + + object NullConstantTypeTest extends TypeTest[Constant, NullConstant]: + def unapply(x: Constant): Option[NullConstant & x.type] = + if x.tag == dotc.core.Constants.NullTag then Some(x.asInstanceOf[NullConstant & x.type]) else None + end NullConstantTypeTest + + object NullConstant extends NullConstantModule: + def apply(): NullConstant = dotc.core.Constants.Constant(null) + def unapply(constant: NullConstant): true = true + end NullConstant + + type ClassOfConstant = dotc.core.Constants.Constant + + object ClassOfConstantTypeTest extends TypeTest[Constant, ClassOfConstant]: + def unapply(x: Constant): Option[ClassOfConstant & x.type] = + if x.tag == dotc.core.Constants.ClazzTag then Some(x.asInstanceOf[ClassOfConstant & x.type]) else None + end ClassOfConstantTypeTest + + object ClassOfConstant extends ClassOfConstantModule: + def apply(x: TypeRepr): ClassOfConstant = + // TODO check that the type is a valid class when creating this constant or let Ycheck do it? + dotc.core.Constants.Constant(x) + def unapply(constant: ClassOfConstant): Some[TypeRepr] = Some(constant.typeValue) + end ClassOfConstant + + object Implicits extends ImplicitsModule: + def search(tpe: TypeRepr): ImplicitSearchResult = + ctx.typer.inferImplicitArg(tpe, Position.ofMacroExpansion.span) + end Implicits + + type ImplicitSearchResult = Tree + + type ImplicitSearchSuccess = Tree + + object ImplicitSearchSuccessTypeTest extends TypeTest[ImplicitSearchResult, ImplicitSearchSuccess]: + def unapply(x: ImplicitSearchResult): Option[ImplicitSearchSuccess & x.type] = + x.tpe match + case _: dotc.typer.Implicits.SearchFailureType => None + case _ => Some(x) + end ImplicitSearchSuccessTypeTest + + given ImplicitSearchSuccessMethods: ImplicitSearchSuccessMethods with + extension (self: ImplicitSearchSuccess) + def tree: Term = self + end extension + end ImplicitSearchSuccessMethods + + type ImplicitSearchFailure = Tree + + object ImplicitSearchFailureTypeTest extends TypeTest[ImplicitSearchResult, ImplicitSearchFailure]: + def unapply(x: ImplicitSearchResult): Option[ImplicitSearchFailure & x.type] = + x.tpe match + case _: dotc.typer.Implicits.SearchFailureType => Some(x) + case _ => None + end ImplicitSearchFailureTypeTest + + given ImplicitSearchFailureMethods: ImplicitSearchFailureMethods with + extension (self: ImplicitSearchFailure) + def explanation: String = + self.tpe.asInstanceOf[dotc.typer.Implicits.SearchFailureType].explanation + end extension + end ImplicitSearchFailureMethods + + type DivergingImplicit = Tree + + object DivergingImplicitTypeTest extends TypeTest[ImplicitSearchResult, DivergingImplicit]: + def unapply(x: ImplicitSearchResult): Option[DivergingImplicit & x.type] = + x.tpe match + case _: dotc.typer.Implicits.DivergingImplicit => Some(x) + case _ => None + end DivergingImplicitTypeTest + + type NoMatchingImplicits = Tree + + object NoMatchingImplicitsTypeTest extends TypeTest[ImplicitSearchResult, NoMatchingImplicits]: + def unapply(x: ImplicitSearchResult): Option[NoMatchingImplicits & x.type] = + x.tpe match + case _: dotc.typer.Implicits.NoMatchingImplicits => Some(x) + case _ => None + end NoMatchingImplicitsTypeTest + + type AmbiguousImplicits = Tree + + object AmbiguousImplicitsTypeTest extends TypeTest[ImplicitSearchResult, AmbiguousImplicits]: + def unapply(x: ImplicitSearchResult): Option[AmbiguousImplicits & x.type] = + x.tpe match + case _: dotc.typer.Implicits.AmbiguousImplicits => Some(x) + case _ => None + end AmbiguousImplicitsTypeTest + + type Symbol = dotc.core.Symbols.Symbol + + object Symbol extends SymbolModule: + def spliceOwner: Symbol = ctx.owner + def requiredPackage(path: String): Symbol = dotc.core.Symbols.requiredPackage(path) + def requiredClass(path: String): Symbol = dotc.core.Symbols.requiredClass(path) + def requiredModule(path: String): Symbol = dotc.core.Symbols.requiredModule(path) + def requiredMethod(path: String): Symbol = dotc.core.Symbols.requiredMethod(path) + def classSymbol(fullName: String): Symbol = dotc.core.Symbols.requiredClass(fullName) + def newMethod(owner: Symbol, name: String, tpe: TypeRepr): Symbol = + newMethod(owner, name, tpe, Flags.EmptyFlags, noSymbol) + def newMethod(owner: Symbol, name: String, tpe: TypeRepr, flags: Flags, privateWithin: Symbol): Symbol = + dotc.core.Symbols.newSymbol(owner, name.toTermName, flags | dotc.core.Flags.Method, tpe, privateWithin) + def newVal(owner: Symbol, name: String, tpe: TypeRepr, flags: Flags, privateWithin: Symbol): Symbol = + dotc.core.Symbols.newSymbol(owner, name.toTermName, flags, tpe, privateWithin) + def newBind(owner: Symbol, name: String, flags: Flags, tpe: TypeRepr): Symbol = + dotc.core.Symbols.newSymbol(owner, name.toTermName, flags | Case, tpe) + def noSymbol: Symbol = dotc.core.Symbols.NoSymbol + end Symbol + + given SymbolMethods: SymbolMethods with + extension (self: Symbol) + def owner: Symbol = self.denot.owner + def maybeOwner: Symbol = self.denot.maybeOwner + def flags: Flags = self.denot.flags + + def privateWithin: Option[TypeRepr] = + val within: Symbol = + self.denot.privateWithin + if (within.exists && !self.is(dotc.core.Flags.Protected)) Some(within.typeRef) + else None + + def protectedWithin: Option[TypeRepr] = + val within: Symbol = + self.denot.privateWithin + if (within.exists && self.is(dotc.core.Flags.Protected)) Some(within.typeRef) + else None + + def name: String = self.denot.name.toString + def fullName: String = self.denot.fullName.toString + def pos: Option[Position] = + if self.exists then Some(self.sourcePos) else None + + def docstring: Option[String] = + import dotc.core.Comments.CommentsContext + val docCtx = ctx.docCtx.getOrElse { + throw new RuntimeException( + "DocCtx could not be found and documentations are unavailable. This is a compiler-internal error." + ) + } + docCtx.docstring(self).map(_.raw) + + def tree: Tree = FromSymbol.definitionFromSym(self) + + def hasAnnotation(annotSym: Symbol): Boolean = + self.denot.hasAnnotation(annotSym) + + def getAnnotation(annotSym: Symbol): Option[Term] = + self.denot.getAnnotation(annotSym).map(_.tree) + + def annotations: List[Term] = + self.denot.annotations.flatMap { + case _: dotc.core.Annotations.BodyAnnotation => Nil + case annot => annot.tree :: Nil + } + + def isDefinedInCurrentRun: Boolean = + self.topLevelClass.asClass.isDefinedInCurrentRun + def isLocalDummy: Boolean = self.denot.isLocalDummy + def isRefinementClass: Boolean = self.denot.isRefinementClass + def isAliasType: Boolean = self.denot.isAliasType + def isAnonymousClass: Boolean = self.denot.isAnonymousClass + def isAnonymousFunction: Boolean = self.denot.isAnonymousFunction + def isAbstractType: Boolean = self.denot.isAbstractType + def isClassConstructor: Boolean = self.denot.isClassConstructor + def isType: Boolean = self.isType + def isTerm: Boolean = self.isTerm + def isPackageDef: Boolean = self.is(dotc.core.Flags.Package) + def isClassDef: Boolean = self.isClass + def isTypeDef: Boolean = + self.isType && !self.isClass && !self.is(dotc.core.Flags.Case) + def isValDef: Boolean = + self.isTerm && !self.is(dotc.core.Flags.Method) && !self.is(dotc.core.Flags.Case/*, FIXME add this check and fix sourcecode butNot = Enum | Module*/) + def isDefDef: Boolean = self.is(dotc.core.Flags.Method) + def isBind: Boolean = + self.is(dotc.core.Flags.Case, butNot = Enum | Module) && !self.isClass + def isNoSymbol: Boolean = self == Symbol.noSymbol + def exists: Boolean = self != Symbol.noSymbol + + def declaredField(name: String): Symbol = + val sym = self.unforcedDecls.find(sym => sym.name == name.toTermName) + if (isField(sym)) sym else dotc.core.Symbols.NoSymbol + + def declaredFields: List[Symbol] = self.unforcedDecls.filter(isField) + + def memberField(name: String): Symbol = + appliedTypeRef(self).allMembers.iterator.map(_.symbol).find { + sym => isField(sym) && sym.name.toString == name + }.getOrElse(dotc.core.Symbols.NoSymbol) + + def memberFields: List[Symbol] = + appliedTypeRef(self).allMembers.iterator.map(_.symbol).collect { + case sym if isField(sym) => sym.asTerm + }.toList + + def declaredMethod(name: String): List[Symbol] = + self.typeRef.decls.iterator.collect { + case sym if isMethod(sym) && sym.name.toString == name => sym.asTerm + }.toList + + def declaredMethods: List[Symbol] = + self.typeRef.decls.iterator.collect { + case sym if isMethod(sym) => sym.asTerm + }.toList + + def memberMethod(name: String): List[Symbol] = + appliedTypeRef(self).allMembers.iterator.map(_.symbol).collect { + case sym if isMethod(sym) && sym.name.toString == name => sym.asTerm + }.toList + + def memberMethods: List[Symbol] = + appliedTypeRef(self).allMembers.iterator.map(_.symbol).collect { + case sym if isMethod(sym) => sym.asTerm + }.toList + + def declaredType(name: String): List[Symbol] = + self.typeRef.decls.iterator.collect { + case sym if sym.isType && sym.name.toString == name => sym.asType + }.toList + + def declaredTypes: List[Symbol] = + self.typeRef.decls.iterator.collect { + case sym if sym.isType => sym.asType + }.toList + + def memberType(name: String): Symbol = + self.unforcedDecls.find(sym => sym.name == name.toTypeName) + + def memberTypes: List[Symbol] = + self.unforcedDecls.filter(_.isType) + + def declarations: List[Symbol] = + self.typeRef.info.decls.toList + + def paramSymss: List[List[Symbol]] = self.denot.paramSymss + def primaryConstructor: Symbol = self.denot.primaryConstructor + def allOverriddenSymbols: Iterator[Symbol] = self.denot.allOverriddenSymbols + def overridingSymbol(ofclazz: Symbol): Symbol = + if ofclazz.isClass then self.denot.overridingSymbol(ofclazz.asClass) + else dotc.core.Symbols.NoSymbol + + def caseFields: List[Symbol] = + if !self.isClass then Nil + else self.asClass.paramAccessors.collect { + case sym if sym.is(dotc.core.Flags.CaseAccessor) => sym.asTerm + } + + def isTypeParam: Boolean = self.isTypeParam + def signature: Signature = self.signature + def moduleClass: Symbol = self.denot.moduleClass + def companionClass: Symbol = self.denot.companionClass + def companionModule: Symbol = self.denot.companionModule + def children: List[Symbol] = self.denot.children + + def show(using printer: Printer[Symbol]): String = printer.show(self) + + end extension + + private def appliedTypeRef(sym: Symbol): TypeRepr = + sym.typeRef.appliedTo(sym.typeParams.map(_.typeRef)) + + private def isMethod(sym: Symbol): Boolean = + sym.isTerm && sym.is(dotc.core.Flags.Method) && !sym.isConstructor + + private def isField(sym: Symbol): Boolean = + sym.isTerm && !sym.is(dotc.core.Flags.Method) + end SymbolMethods + + type Signature = dotc.core.Signature + + object Signature extends SignatureModule: + def unapply(sig: Signature): (List[String | Int], String) = + (sig.paramSigs, sig.resultSig) + end Signature + + given SignatureMethods: SignatureMethods with + extension (self: Signature) + def paramSigs: List[String | Int] = + self.paramsSig.map { + case paramSig: dotc.core.Names.TypeName => + paramSig.toString + case paramSig: Int => + paramSig + } + def resultSig: String = + self.resSig.toString + end extension + end SignatureMethods + + object defn extends defnModule: + def RootPackage: Symbol = dotc.core.Symbols.defn.RootPackage + def RootClass: Symbol = dotc.core.Symbols.defn.RootClass + def EmptyPackageClass: Symbol = dotc.core.Symbols.defn.EmptyPackageClass + def ScalaPackage: Symbol = dotc.core.Symbols.defn.ScalaPackageVal + def ScalaPackageClass: Symbol = dotc.core.Symbols.defn.ScalaPackageClass + def AnyClass: Symbol = dotc.core.Symbols.defn.AnyClass + def MatchableClass: Symbol = dotc.core.Symbols.defn.MatchableClass + def AnyValClass: Symbol = dotc.core.Symbols.defn.AnyValClass + def ObjectClass: Symbol = dotc.core.Symbols.defn.ObjectClass + def AnyRefClass: Symbol = dotc.core.Symbols.defn.AnyRefAlias + def NullClass: Symbol = dotc.core.Symbols.defn.NullClass + def NothingClass: Symbol = dotc.core.Symbols.defn.NothingClass + def UnitClass: Symbol = dotc.core.Symbols.defn.UnitClass + def ByteClass: Symbol = dotc.core.Symbols.defn.ByteClass + def ShortClass: Symbol = dotc.core.Symbols.defn.ShortClass + def CharClass: Symbol = dotc.core.Symbols.defn.CharClass + def IntClass: Symbol = dotc.core.Symbols.defn.IntClass + def LongClass: Symbol = dotc.core.Symbols.defn.LongClass + def FloatClass: Symbol = dotc.core.Symbols.defn.FloatClass + def DoubleClass: Symbol = dotc.core.Symbols.defn.DoubleClass + def BooleanClass: Symbol = dotc.core.Symbols.defn.BooleanClass + def StringClass: Symbol = dotc.core.Symbols.defn.StringClass + def ClassClass: Symbol = dotc.core.Symbols.defn.ClassClass + def ArrayClass: Symbol = dotc.core.Symbols.defn.ArrayClass + def PredefModule: Symbol = dotc.core.Symbols.defn.ScalaPredefModule + def Predef_classOf: Symbol = dotc.core.Symbols.defn.Predef_classOf + def JavaLangPackage: Symbol = dotc.core.Symbols.defn.JavaLangPackageVal + def ArrayModule: Symbol = dotc.core.Symbols.defn.ArrayModule + def Array_apply: Symbol = dotc.core.Symbols.defn.Array_apply + def Array_clone: Symbol = dotc.core.Symbols.defn.Array_clone + def Array_length: Symbol = dotc.core.Symbols.defn.Array_length + def Array_update: Symbol = dotc.core.Symbols.defn.Array_update + def RepeatedParamClass: Symbol = dotc.core.Symbols.defn.RepeatedParamClass + def RepeatedAnnot: Symbol = dotc.core.Symbols.defn.RepeatedAnnot + def OptionClass: Symbol = dotc.core.Symbols.defn.OptionClass + def NoneModule: Symbol = dotc.core.Symbols.defn.NoneModule + def SomeModule: Symbol = dotc.core.Symbols.defn.SomeClass.companionModule + def ProductClass: Symbol = dotc.core.Symbols.defn.ProductClass + def FunctionClass(arity: Int, isImplicit: Boolean = false, isErased: Boolean = false): Symbol = + dotc.core.Symbols.defn.FunctionClass(arity, isImplicit, isErased) + def TupleClass(arity: Int): Symbol = + dotc.core.Symbols.defn.TupleType(arity).classSymbol.asClass + def isTupleClass(sym: Symbol): Boolean = + dotc.core.Symbols.defn.isTupleClass(sym) + def ScalaPrimitiveValueClasses: List[Symbol] = + UnitClass :: BooleanClass :: ScalaNumericValueClasses + def ScalaNumericValueClasses: List[Symbol] = + ByteClass :: ShortClass :: IntClass :: LongClass :: FloatClass :: DoubleClass :: CharClass :: Nil + end defn + + type Flags = dotc.core.Flags.FlagSet + + object Flags extends FlagsModule: + def Abstract: Flags = dotc.core.Flags.Abstract + def Artifact: Flags = dotc.core.Flags.Artifact + def Case: Flags = dotc.core.Flags.Case + def CaseAccessor: Flags = dotc.core.Flags.CaseAccessor + def Contravariant: Flags = dotc.core.Flags.Contravariant + def Covariant: Flags = dotc.core.Flags.Covariant + def Deferred: Flags = dotc.core.Flags.Deferred + def EmptyFlags = dotc.core.Flags.EmptyFlags + def Enum: Flags = dotc.core.Flags.Enum + def Erased: Flags = dotc.core.Flags.Erased + def Exported: Flags = dotc.core.Flags.Exported + def ExtensionMethod: Flags = dotc.core.Flags.ExtensionMethod + def FieldAccessor: Flags = dotc.core.Flags.Accessor + def Final: Flags = dotc.core.Flags.Final + def Given: Flags = dotc.core.Flags.Given + def HasDefault: Flags = dotc.core.Flags.HasDefault + def Implicit: Flags = dotc.core.Flags.Implicit + def Infix: Flags = dotc.core.Flags.Infix + def Inline: Flags = dotc.core.Flags.Inline + def JavaDefined: Flags = dotc.core.Flags.JavaDefined + def JavaStatic: Flags = dotc.core.Flags.JavaStatic + def Lazy: Flags = dotc.core.Flags.Lazy + def Local: Flags = dotc.core.Flags.Local + def Macro: Flags = dotc.core.Flags.Macro + def Method: Flags = dotc.core.Flags.Method + def Module: Flags = dotc.core.Flags.Module + def Mutable: Flags = dotc.core.Flags.Mutable + def NoInits: Flags = dotc.core.Flags.NoInits + def Opaque: Flags = dotc.core.Flags.Opaque + def Open: Flags = dotc.core.Flags.Open + def Override: Flags = dotc.core.Flags.Override + def Package: Flags = dotc.core.Flags.Package + def Param: Flags = dotc.core.Flags.Param + def ParamAccessor: Flags = dotc.core.Flags.ParamAccessor + def Private: Flags = dotc.core.Flags.Private + def PrivateLocal: Flags = dotc.core.Flags.PrivateLocal + def Protected: Flags = dotc.core.Flags.Protected + def Scala2x: Flags = dotc.core.Flags.Scala2x + def Sealed: Flags = dotc.core.Flags.Sealed + def StableRealizable: Flags = dotc.core.Flags.StableRealizable + def Static: Flags = dotc.core.Flags.JavaStatic + def Synthetic: Flags = dotc.core.Flags.Synthetic + def Trait: Flags = dotc.core.Flags.Trait + def Transparent: Flags = dotc.core.Flags.Transparent + end Flags + + given FlagsMethods: FlagsMethods with + extension (self: Flags) + def is(that: Flags): Boolean = self.isAllOf(that) + def |(that: Flags): Flags = dotc.core.Flags.or(self, that) // TODO: Replace with dotc.core.Flags.|(self)(that) once extension names have stabilized + def &(that: Flags): Flags = dotc.core.Flags.and(self, that)// TODO: Replace with dotc.core.Flags.&(self)(that) once extension names have stabilized + def show: String = Extractors.showFlags(using QuotesImpl.this)(self) + end extension + end FlagsMethods + + type Position = dotc.util.SourcePosition + + object Position extends PositionModule: + def ofMacroExpansion: dotc.util.SourcePosition = + MacroExpansion.position.getOrElse(dotc.util.SourcePosition(ctx.source, dotc.util.Spans.NoSpan)) + def apply(sourceFile: SourceFile, start: Int, end: Int): Position = + dotc.util.SourcePosition(sourceFile, dotc.util.Spans.Span(start, end)) + end Position + + given PositionMethods: PositionMethods with + extension (self: Position) + def start: Int = self.start + def end: Int = self.end + def sourceFile: SourceFile = self.source + def startLine: Int = self.startLine + def endLine: Int = self.endLine + def startColumn: Int = self.startColumn + def endColumn: Int = self.endColumn + def sourceCode: Option[String] = + // TODO detect when we do not have a source and return None + Some(new String(self.source.content(), self.start, self.end - self.start)) + end extension + end PositionMethods + + type SourceFile = dotc.util.SourceFile + + object SourceFile extends SourceFileModule { + def current: SourceFile = ctx.compilationUnit.source + } + + given SourceFileMethods: SourceFileMethods with + extension (self: SourceFile) + def jpath: java.nio.file.Path = self.file.jpath + def content: Option[String] = + // TODO detect when we do not have a source and return None + Some(new String(self.content())) + end extension + end SourceFileMethods + + object report extends reportModule: + + def error(msg: String): Unit = + dotc.report.error(msg, Position.ofMacroExpansion) + + def error(msg: String, expr: Expr[Any]): Unit = + dotc.report.error(msg, asTerm(expr).pos) + + def error(msg: String, pos: Position): Unit = + dotc.report.error(msg, pos) + + def throwError(msg: String): Nothing = + error(msg) + throw new scala.quoted.runtime.StopMacroExpansion + + def throwError(msg: String, expr: Expr[Any]): Nothing = + error(msg, expr) + throw new scala.quoted.runtime.StopMacroExpansion + + def throwError(msg: String, pos: Position): Nothing = + error(msg, pos) + throw new scala.quoted.runtime.StopMacroExpansion + + def warning(msg: String): Unit = + dotc.report.warning(msg, Position.ofMacroExpansion) + + def warning(msg: String, expr: Expr[Any]): Unit = + dotc.report.warning(msg, asTerm(expr).pos) + + def warning(msg: String, pos: Position): Unit = + dotc.report.warning(msg, pos) + + end report + + private def optional[T <: dotc.ast.Trees.Tree[?]](tree: T): Option[tree.type] = + if tree.isEmpty then None else Some(tree) + + private def withDefaultPos[T <: Tree](fn: Context ?=> T): T = + fn(using ctx.withSource(Position.ofMacroExpansion.source)).withSpan(Position.ofMacroExpansion.span) + + /** Checks that all definitions in this tree have the expected owner. + * Nested definitions are ignored and assumed to be correct by construction. + */ + private def yCheckedOwners(tree: Option[Tree], owner: Symbol): tree.type = + if yCheck then + tree match + case Some(tree) => + yCheckOwners(tree, owner) + case _ => + tree + + /** Checks that all definitions in this tree have the expected owner. + * Nested definitions are ignored and assumed to be correct by construction. + */ + private def yCheckedOwners(tree: Tree, owner: Symbol): tree.type = + if yCheck then + yCheckOwners(tree, owner) + tree + + /** Checks that all definitions in this tree have the expected owner. + * Nested definitions are ignored and assumed to be correct by construction. + */ + private def yCheckOwners(tree: Tree, owner: Symbol): Unit = + new tpd.TreeTraverser { + def traverse(t: Tree)(using Context): Unit = + t match + case t: tpd.DefTree => + val defOwner = t.symbol.owner + assert(defOwner == owner, + s"""Tree had an unexpected owner for ${t.symbol} + |Expected: $owner (${owner.fullName}) + |But was: $defOwner (${defOwner.fullName}) + | + | + |The code of the definition of ${t.symbol} is + |${Printer.TreeCode.show(t)} + | + |which was found in the code + |${Printer.TreeCode.show(tree)} + | + |which has the AST representation + |${Printer.TreeStructure.show(tree)} + | + |""".stripMargin) + case _ => traverseChildren(t) + }.traverse(tree) + + object Printer extends PrinterModule: + + lazy val TreeCode: Printer[Tree] = new Printer[Tree]: + def show(tree: Tree): String = + SourceCode.showTree(using QuotesImpl.this)(tree)(SyntaxHighlight.plain, fullNames = true) + + lazy val TreeShortCode: Printer[Tree] = new Printer[Tree]: + def show(tree: Tree): String = + SourceCode.showTree(using QuotesImpl.this)(tree)(SyntaxHighlight.plain, fullNames = false) + + lazy val TreeAnsiCode: Printer[Tree] = new Printer[Tree]: + def show(tree: Tree): String = + SourceCode.showTree(using QuotesImpl.this)(tree)(SyntaxHighlight.ANSI, fullNames = true) + + lazy val TreeStructure: Printer[Tree] = new Printer[Tree]: + def show(tree: Tree): String = + Extractors.showTree(using QuotesImpl.this)(tree) + + lazy val TypeReprCode: Printer[TypeRepr] = new Printer[TypeRepr]: + def show(tpe: TypeRepr): String = + SourceCode.showType(using QuotesImpl.this)(tpe)(SyntaxHighlight.plain, fullNames = true) + + lazy val TypeReprShortCode: Printer[TypeRepr] = new Printer[TypeRepr]: + def show(tpe: TypeRepr): String = + SourceCode.showType(using QuotesImpl.this)(tpe)(SyntaxHighlight.plain, fullNames = false) + + lazy val TypeReprAnsiCode: Printer[TypeRepr] = new Printer[TypeRepr]: + def show(tpe: TypeRepr): String = + SourceCode.showType(using QuotesImpl.this)(tpe)(SyntaxHighlight.ANSI, fullNames = true) + + lazy val TypeReprStructure: Printer[TypeRepr] = new Printer[TypeRepr]: + def show(tpe: TypeRepr): String = + Extractors.showType(using QuotesImpl.this)(tpe) + + lazy val ConstantCode: Printer[Constant] = new Printer[Constant]: + def show(const: Constant): String = + const.show(using ctx.fresh.setSetting(ctx.settings.color, "never")) + + lazy val ConstantStructure: Printer[Constant] = new Printer[Constant]: + def show(const: Constant): String = + Extractors.showConstant(using QuotesImpl.this)(const) + + end Printer + end reflect + + def unpickleExpr[T](pickled: String | List[String], typeHole: (Int, Seq[Any]) => scala.quoted.Type[?], termHole: (Int, Seq[Any], scala.quoted.Quotes) => scala.quoted.Expr[?]): scala.quoted.Expr[T] = + val tree = PickledQuotes.unpickleTerm(pickled, typeHole, termHole) + new ExprImpl(tree, hash).asInstanceOf[scala.quoted.Expr[T]] + + def unpickleType[T <: AnyKind](pickled: String | List[String], typeHole: (Int, Seq[Any]) => scala.quoted.Type[?], termHole: (Int, Seq[Any], scala.quoted.Quotes) => scala.quoted.Expr[?]): scala.quoted.Type[T] = + val tree = PickledQuotes.unpickleTypeTree(pickled, typeHole, termHole) + new TypeImpl(tree, hash).asInstanceOf[scala.quoted.Type[T]] + + object ExprMatch extends ExprMatchModule: + def unapply[TypeBindings <: Tuple, Tup <: Tuple](scrutinee: scala.quoted.Expr[Any])(using pattern: scala.quoted.Expr[Any]): Option[Tup] = + val scrutineeTree = reflect.asTerm(scrutinee) + val patternTree = reflect.asTerm(pattern) + treeMatch(scrutineeTree, patternTree).asInstanceOf[Option[Tup]] + end ExprMatch + + object TypeMatch extends TypeMatchModule: + def unapply[TypeBindings <: Tuple, Tup <: Tuple](scrutinee: scala.quoted.Type[?])(using pattern: scala.quoted.Type[?]): Option[Tup] = + val scrutineeTree = reflect.TypeTree.of(using scrutinee) + val patternTree = reflect.TypeTree.of(using pattern) + treeMatch(scrutineeTree, patternTree).asInstanceOf[Option[Tup]] + end TypeMatch + + private def treeMatch(scrutinee: reflect.Tree, pattern: reflect.Tree): Option[Tuple] = { + import reflect._ + def isTypeHoleDef(tree: Tree): Boolean = + tree match + case tree: TypeDef => + tree.symbol.hasAnnotation(dotc.core.Symbols.defn.QuotedRuntimePatterns_patternTypeAnnot) + case _ => false + + def extractTypeHoles(pat: Term): (Term, List[Symbol]) = + pat match + case tpd.Inlined(_, Nil, pat2) => extractTypeHoles(pat2) + case tpd.Block(stats @ ((typeHole: TypeDef) :: _), expr) if isTypeHoleDef(typeHole) => + val holes = stats.takeWhile(isTypeHoleDef).map(_.symbol) + val otherStats = stats.dropWhile(isTypeHoleDef) + (tpd.cpy.Block(pat)(otherStats, expr), holes) + case _ => + (pat, Nil) + + val (pat1, typeHoles) = extractTypeHoles(pattern) + + val ctx1 = + if typeHoles.isEmpty then ctx + else + val ctx1 = ctx.fresh.setFreshGADTBounds.addMode(dotc.core.Mode.GadtConstraintInference) + ctx1.gadt.addToConstraint(typeHoles) + ctx1 + + val qctx1 = QuotesImpl()(using ctx1) + + val matcher = new Matcher.QuoteMatcher[qctx1.type](qctx1) { + def patternHoleSymbol: qctx1.reflect.Symbol = dotc.core.Symbols.defn.QuotedRuntimePatterns_patternHole.asInstanceOf + def higherOrderHoleSymbol: qctx1.reflect.Symbol = dotc.core.Symbols.defn.QuotedRuntimePatterns_higherOrderHole.asInstanceOf + } + + val matchings = + if pat1.isType then matcher.termMatch(scrutinee.asInstanceOf[matcher.qctx.reflect.Term], pat1.asInstanceOf[matcher.qctx.reflect.Term]) + else matcher.termMatch(scrutinee.asInstanceOf[matcher.qctx.reflect.Term], pat1.asInstanceOf[matcher.qctx.reflect.Term]) + + // val matchings = matcher.termMatch(scrutinee, pattern) + if typeHoles.isEmpty then matchings + else { + // After matching and doing all subtype checks, we have to approximate all the type bindings + // that we have found, seal them in a quoted.Type and add them to the result + def typeHoleApproximation(sym: Symbol) = + ctx1.gadt.approximation(sym, !sym.hasAnnotation(dotc.core.Symbols.defn.QuotedRuntimePatterns_fromAboveAnnot)).asInstanceOf[qctx1.reflect.TypeRepr].asType + matchings.map { tup => + Tuple.fromIArray(typeHoles.map(typeHoleApproximation).toArray.asInstanceOf[IArray[Object]]) ++ tup + } + } + } + + private[this] val hash = QuotesImpl.scopeId(using ctx) + override def hashCode: Int = hash + +end QuotesImpl diff --git a/compiler/src/scala/quoted/runtime/impl/QuotesImpl.scala b/compiler/src-non-bootstrapped/scala/quoted/runtime/impl/QuotesImpl.scala similarity index 99% rename from compiler/src/scala/quoted/runtime/impl/QuotesImpl.scala rename to compiler/src-non-bootstrapped/scala/quoted/runtime/impl/QuotesImpl.scala index 5500bef5c96a..ee2d419482a8 100644 --- a/compiler/src/scala/quoted/runtime/impl/QuotesImpl.scala +++ b/compiler/src-non-bootstrapped/scala/quoted/runtime/impl/QuotesImpl.scala @@ -62,7 +62,7 @@ class QuotesImpl private (using val ctx: Context) extends Quotes, QuoteUnpickler /** Convert this to an `quoted.Expr[X]` if this expression is a valid expression of type `X` or throws */ def asExprOf(using scala.quoted.Type[X]): scala.quoted.Expr[X] = { - if isExprOf[X] then + if self.isExprOf[X] then self.asInstanceOf[scala.quoted.Expr[X]] else throw Exception( @@ -257,17 +257,20 @@ class QuotesImpl private (using val ctx: Context) extends Quotes, QuoteUnpickler object DefDef extends DefDefModule: def apply(symbol: Symbol, rhsFn: List[TypeRepr] => List[List[Term]] => Option[Term]): DefDef = - withDefaultPos(tpd.polyDefDef(symbol.asTerm, tparams => vparamss => yCheckedOwners(rhsFn(tparams)(vparamss), symbol).getOrElse(tpd.EmptyTree))) + withDefaultPos(tpd.DefDef(symbol.asTerm, prefss => { + val (tparams, vparamss) = tpd.splitArgs(prefss) + yCheckedOwners(rhsFn(tparams.map(_.tpe))(vparamss), symbol).getOrElse(tpd.EmptyTree) + })) def copy(original: Tree)(name: String, typeParams: List[TypeDef], paramss: List[List[ValDef]], tpt: TypeTree, rhs: Option[Term]): DefDef = - tpd.cpy.DefDef(original)(name.toTermName, typeParams, paramss, tpt, yCheckedOwners(rhs, original.symbol).getOrElse(tpd.EmptyTree)) + tpd.cpy.DefDef(original)(name.toTermName, tpd.joinParams(typeParams, paramss), tpt, yCheckedOwners(rhs, original.symbol).getOrElse(tpd.EmptyTree)) def unapply(ddef: DefDef): (String, List[TypeDef], List[List[ValDef]], TypeTree, Option[Term]) = - (ddef.name.toString, ddef.typeParams, ddef.paramss, ddef.tpt, optional(ddef.rhs)) + (ddef.name.toString, ddef.typeParams, ddef.termParamss, ddef.tpt, optional(ddef.rhs)) end DefDef given DefDefMethods: DefDefMethods with extension (self: DefDef) - def typeParams: List[TypeDef] = self.tparams - def paramss: List[List[ValDef]] = self.vparamss + def typeParams: List[TypeDef] = self.leadingTypeParams // TODO: adapt to multiple type parameter clauses + def paramss: List[List[ValDef]] = self.termParamss def returnTpt: TypeTree = self.tpt def rhs: Option[Term] = optional(self.rhs) end extension @@ -380,7 +383,7 @@ class QuotesImpl private (using val ctx: Context) extends Quotes, QuoteUnpickler } val closureTpe = Types.MethodType(mtpe.paramNames, mtpe.paramInfos, closureResType) val closureMethod = dotc.core.Symbols.newSymbol(owner, nme.ANON_FUN, Synthetic | Method, closureTpe) - tpd.Closure(closureMethod, tss => new tpd.TreeOps(self).appliedToArgs(tss.head).etaExpand(closureMethod)) + tpd.Closure(closureMethod, tss => new tpd.TreeOps(self).appliedToTermArgs(tss.head).etaExpand(closureMethod)) case _ => self } diff --git a/compiler/src/dotty/tools/backend/jvm/BCodeSkelBuilder.scala b/compiler/src/dotty/tools/backend/jvm/BCodeSkelBuilder.scala index e3f740e3abee..9401307e8d62 100644 --- a/compiler/src/dotty/tools/backend/jvm/BCodeSkelBuilder.scala +++ b/compiler/src/dotty/tools/backend/jvm/BCodeSkelBuilder.scala @@ -181,7 +181,7 @@ trait BCodeSkelBuilder extends BCodeHelpers { def rewire(stat: Tree) = thisMap.transform(stat).changeOwner(claszSymbol.primaryConstructor, clInitSymbol) - val callConstructor = New(claszSymbol.typeRef).select(claszSymbol.primaryConstructor).appliedToArgs(Nil) + val callConstructor = New(claszSymbol.typeRef).select(claszSymbol.primaryConstructor).appliedToTermArgs(Nil) val assignModuleField = Assign(ref(moduleField), callConstructor) val remainingConstrStatsSubst = remainingConstrStats.map(rewire) val clinit = clinits match { @@ -667,7 +667,7 @@ trait BCodeSkelBuilder extends BCodeHelpers { val enclosingClass = origSym.owner.asClass new TreeTypeMap( typeMap = _.substThis(enclosingClass, selfParamRef.symbol.termRef) - .subst(dd.vparamss.head.map(_.symbol), regularParamRefs.map(_.symbol.termRef)), + .subst(dd.termParamss.head.map(_.symbol), regularParamRefs.map(_.symbol.termRef)), treeMap = { case tree: This if tree.symbol == enclosingClass => selfParamRef case tree => tree @@ -714,7 +714,7 @@ trait BCodeSkelBuilder extends BCodeHelpers { def genDefDef(dd: DefDef): Unit = { val rhs = dd.rhs - val vparamss = dd.vparamss + val vparamss = dd.termParamss // the only method whose implementation is not emitted: getClass() if (dd.symbol eq defn.Any_getClass) { return } assert(mnode == null, "GenBCode detected nested method.") diff --git a/compiler/src/dotty/tools/backend/sjs/JSCodeGen.scala b/compiler/src/dotty/tools/backend/sjs/JSCodeGen.scala index 564c8b1e7c33..0fc08751a973 100644 --- a/compiler/src/dotty/tools/backend/sjs/JSCodeGen.scala +++ b/compiler/src/dotty/tools/backend/sjs/JSCodeGen.scala @@ -1035,7 +1035,7 @@ class JSCodeGen()(using genCtx: Context) { private def genMethodWithCurrentLocalNameScope(dd: DefDef): Option[js.MethodDef] = { implicit val pos = dd.span val sym = dd.symbol - val vparamss = dd.vparamss + val vparamss = dd.termParamss val rhs = dd.rhs withScopedVars( diff --git a/compiler/src/dotty/tools/dotc/ast/Desugar.scala b/compiler/src/dotty/tools/dotc/ast/Desugar.scala index 65085b39e7bc..35798f934f46 100644 --- a/compiler/src/dotty/tools/dotc/ast/Desugar.scala +++ b/compiler/src/dotty/tools/dotc/ast/Desugar.scala @@ -177,11 +177,10 @@ object desugar { // The rhs gets filled in later, when field is generated and getter has parameters (see Memoize miniphase) val setterRhs = if (vdef.rhs.isEmpty) EmptyTree else unitLiteral val setter = cpy.DefDef(vdef)( - name = valName.setterName, - tparams = Nil, - vparamss = (setterParam :: Nil) :: Nil, - tpt = TypeTree(defn.UnitType), - rhs = setterRhs + name = valName.setterName, + paramss = (setterParam :: Nil) :: Nil, + tpt = TypeTree(defn.UnitType), + rhs = setterRhs ).withMods((mods | Accessor) &~ (CaseAccessor | GivenOrImplicit | Lazy)) Thicket(vdef1, setter) } @@ -195,6 +194,15 @@ object desugar { ValDef(epname, tpt, EmptyTree).withFlags(paramFlags | implicitFlag) } + def mapParamss(paramss: List[ParamClause]) + (mapTypeParam: TypeDef => TypeDef) + (mapTermParam: ValDef => ValDef)(using Context): List[ParamClause] = + paramss.mapConserve { + case TypeDefs(tparams) => tparams.mapConserve(mapTypeParam) + case ValDefs(vparams) => vparams.mapConserve(mapTermParam) + case _ => ??? // impossible + } + /** 1. Expand context bounds to evidence params. E.g., * * def f[T >: L <: H : B](params) @@ -209,83 +217,100 @@ object desugar { * def f$default$1[T] = 1 * def f$default$2[T](x: Int) = x + "m" */ - private def defDef(meth0: DefDef, isPrimaryConstructor: Boolean = false)(using Context): Tree = { - val meth @ DefDef(_, tparams, vparamss, tpt, rhs) = meth0 - val methName = normalizeName(meth, tpt).asTermName - val mods = meth.mods - val epbuf = ListBuffer[ValDef]() - def desugarContextBounds(rhs: Tree): Tree = rhs match { + private def defDef(meth: DefDef, isPrimaryConstructor: Boolean = false)(using Context): Tree = + addDefaultGetters(elimContextBounds(meth, isPrimaryConstructor)) + + private def elimContextBounds(meth: DefDef, isPrimaryConstructor: Boolean)(using Context): DefDef = + val DefDef(_, paramss, tpt, rhs) = meth + val evidenceParamBuf = ListBuffer[ValDef]() + + def desugarContextBounds(rhs: Tree): Tree = rhs match case ContextBounds(tbounds, cxbounds) => val iflag = if sourceVersion.isAtLeast(`3.1`) then Given else Implicit - epbuf ++= makeImplicitParameters(cxbounds, iflag, forPrimaryConstructor = isPrimaryConstructor) + evidenceParamBuf ++= makeImplicitParameters( + cxbounds, iflag, forPrimaryConstructor = isPrimaryConstructor) tbounds case LambdaTypeTree(tparams, body) => cpy.LambdaTypeTree(rhs)(tparams, desugarContextBounds(body)) case _ => rhs - } - def dropContextBounds(tparam: TypeDef): TypeDef = { - def dropInRhs(rhs: Tree): Tree = rhs match { + val paramssNoContextBounds = + mapParamss(paramss) { + tparam => cpy.TypeDef(tparam)(rhs = desugarContextBounds(tparam.rhs)) + }(identity) + + rhs match + case MacroTree(call) => + cpy.DefDef(meth)(rhs = call).withMods(meth.mods | Macro | Erased) + case _ => + addEvidenceParams( + cpy.DefDef(meth)( + name = normalizeName(meth, tpt).asTermName, + paramss = paramssNoContextBounds), + evidenceParamBuf.toList) + end elimContextBounds + + def addDefaultGetters(meth: DefDef)(using Context): Tree = + + /** The longest prefix of parameter lists in =paramss whose total number of + * ValDefs does not exceed `n` + */ + def takeUpTo(paramss: List[ParamClause], n: Int): List[ParamClause] = paramss match + case ValDefs(vparams) :: paramss1 => + val len = vparams.length + if len <= n then vparams :: takeUpTo(paramss1, n - len) else Nil + case TypeDefs(tparams) :: paramss1 => + tparams :: takeUpTo(paramss1, n) + case _ => + Nil + + def dropContextBounds(tparam: TypeDef): TypeDef = + def dropInRhs(rhs: Tree): Tree = rhs match case ContextBounds(tbounds, _) => tbounds case rhs @ LambdaTypeTree(tparams, body) => cpy.LambdaTypeTree(rhs)(tparams, dropInRhs(body)) case _ => rhs - } cpy.TypeDef(tparam)(rhs = dropInRhs(tparam.rhs)) - } - - val tparams1 = tparams mapConserve { tparam => - cpy.TypeDef(tparam)(rhs = desugarContextBounds(tparam.rhs)) - } - - val meth1 = - rhs match - case MacroTree(call) => cpy.DefDef(meth)(rhs = call).withMods(mods | Macro | Erased) - case _ => addEvidenceParams(cpy.DefDef(meth)(name = methName, tparams = tparams1), epbuf.toList) - /** The longest prefix of parameter lists in vparamss whose total length does not exceed `n` */ - def takeUpTo(vparamss: List[List[ValDef]], n: Int): List[List[ValDef]] = vparamss match { - case vparams :: vparamss1 => - val len = vparams.length - if (n >= len) vparams :: takeUpTo(vparamss1, n - len) else Nil - case _ => - Nil + def paramssNoRHS = mapParamss(meth.paramss)(identity) { + vparam => + if vparam.rhs.isEmpty then vparam + else cpy.ValDef(vparam)(rhs = EmptyTree).withMods(vparam.mods | HasDefault) } - def normalizedVparamss = meth1.vparamss.nestedMapConserve(vparam => - if vparam.rhs.isEmpty then vparam - else cpy.ValDef(vparam)(rhs = EmptyTree).withMods(vparam.mods | HasDefault) - ) + def getterParamss(n: Int): List[ParamClause] = + mapParamss(takeUpTo(paramssNoRHS, n)) { + tparam => dropContextBounds(toDefParam(tparam, keepAnnotations = true)) + } { + vparam => toDefParam(vparam, keepAnnotations = true, keepDefault = false) + } - def defaultGetters(vparamss: List[List[ValDef]], n: Int): List[DefDef] = vparamss match { - case (vparam :: vparams) :: vparamss1 => + def defaultGetters(paramss: List[ParamClause], n: Int): List[DefDef] = paramss match + case ValDefs(vparam :: vparams) :: paramss1 => def defaultGetter: DefDef = DefDef( - name = DefaultGetterName(methName, n), - tparams = meth.tparams.map(tparam => dropContextBounds(toDefParam(tparam, keepAnnotations = true))), - vparamss = takeUpTo(normalizedVparamss.nestedMap(toDefParam(_, keepAnnotations = true, keepDefault = false)), n), + name = DefaultGetterName(meth.name, n), + paramss = getterParamss(n), tpt = TypeTree(), rhs = vparam.rhs ) - .withMods(Modifiers(mods.flags & (AccessFlags | Synthetic), mods.privateWithin)) - val rest = defaultGetters(vparams :: vparamss1, n + 1) - if (vparam.rhs.isEmpty) rest else defaultGetter :: rest - case Nil :: vparamss1 => - defaultGetters(vparamss1, n) - case nil => + .withMods(Modifiers( + meth.mods.flags & (AccessFlags | Synthetic), + meth.mods.privateWithin)) + val rest = defaultGetters(vparams :: paramss1, n + 1) + if vparam.rhs.isEmpty then rest else defaultGetter :: rest + case _ :: paramss1 => // skip empty parameter lists and type parameters + defaultGetters(paramss1, n) + case Nil => Nil - } - val defGetters = defaultGetters(meth1.vparamss, 0) - if (defGetters.isEmpty) meth1 - else { - val meth2 = cpy.DefDef(meth1)(vparamss = normalizedVparamss) - Thicket(meth2 :: defGetters) - } - } + val defGetters = defaultGetters(meth.paramss, 0) + if defGetters.isEmpty then meth + else Thicket(cpy.DefDef(meth)(paramss = paramssNoRHS) :: defGetters) + end addDefaultGetters /** Add an explicit ascription to the `expectedTpt` to every tail splice. * @@ -323,26 +348,28 @@ object desugar { adaptToExpectedTpt(tree) } - // Add all evidence parameters in `params` as implicit parameters to `meth` */ + /** Add all evidence parameters in `params` as implicit parameters to `meth`. + * If the parameters of `meth` end in an implicit parameter list or using clause, + * evidence parameters are added in front of that list. Otherwise they are added + * as a separate parameter clause. + */ private def addEvidenceParams(meth: DefDef, params: List[ValDef])(using Context): DefDef = - params match { + params match case Nil => meth case evidenceParams => - val vparamss1 = meth.vparamss.reverse match { - case (vparams @ (vparam :: _)) :: rvparamss if vparam.mods.isOneOf(GivenOrImplicit) => - ((evidenceParams ++ vparams) :: rvparamss).reverse + val paramss1 = meth.paramss.reverse match + case ValDefs(vparams @ (vparam :: _)) :: rparamss if vparam.mods.isOneOf(GivenOrImplicit) => + ((evidenceParams ++ vparams) :: rparamss).reverse case _ => - meth.vparamss :+ evidenceParams - } - cpy.DefDef(meth)(vparamss = vparamss1) - } + meth.paramss :+ evidenceParams + cpy.DefDef(meth)(paramss = paramss1) /** The implicit evidence parameters of `meth`, as generated by `desugar.defDef` */ private def evidenceParams(meth: DefDef)(using Context): List[ValDef] = - meth.vparamss.reverse match { - case (vparams @ (vparam :: _)) :: _ if vparam.mods.isOneOf(GivenOrImplicit) => - vparams.dropWhile(!_.name.is(EvidenceParamName)) + meth.paramss.reverse match { + case ValDefs(vparams @ (vparam :: _)) :: _ if vparam.mods.isOneOf(GivenOrImplicit) => + vparams.takeWhile(_.name.is(EvidenceParamName)) case _ => Nil } @@ -411,8 +438,8 @@ object desugar { val isValueClass = parents.nonEmpty && isAnyVal(parents.head) // This is not watertight, but `extends AnyVal` will be replaced by `inline` later. - val originalTparams = constr1.tparams - val originalVparamss = constr1.vparamss + val originalTparams = constr1.leadingTypeParams + val originalVparamss = asTermOnly(constr1.trailingParamss) lazy val derivedEnumParams = enumClass.typeParams.map(derivedTypeParamWithVariance) val impliedTparams = if (isEnumCase) { @@ -451,7 +478,7 @@ object desugar { constrVparamss.nestedMap(vparam => derivedTermParam(vparam).withAnnotations(Nil)) - val constr = cpy.DefDef(constr1)(tparams = constrTparams, vparamss = constrVparamss) + val constr = cpy.DefDef(constr1)(paramss = joinParams(constrTparams, constrVparamss)) val (normalizedBody, enumCases, enumCompanionRef) = { // Add constructor type parameters and evidence implicit parameters @@ -461,7 +488,7 @@ object desugar { decompose( defDef( addEvidenceParams( - cpy.DefDef(ddef)(tparams = constrTparams ++ ddef.tparams), + cpy.DefDef(ddef)(paramss = joinParams(constrTparams, ddef.paramss)), evidenceParams(constr1).map(toDefParam(_, keepAnnotations = false, keepDefault = false))))) case stat => stat @@ -584,14 +611,14 @@ object desugar { // two errors without @uncheckedVariance, one of them spurious. val (caseClassMeths, enumScaffolding) = { def syntheticProperty(name: TermName, tpt: Tree, rhs: Tree) = - DefDef(name, Nil, Nil, tpt, rhs).withMods(synthetic) + DefDef(name, Nil, tpt, rhs).withMods(synthetic) def productElemMeths = val caseParams = derivedVparamss.head.toArray val selectorNamesInBody = normalizedBody.collect { case vdef: ValDef if vdef.name.isSelectorName => vdef.name - case ddef: DefDef if ddef.name.isSelectorName && ddef.tparams.isEmpty && ddef.vparamss.isEmpty => + case ddef: DefDef if ddef.name.isSelectorName && ddef.paramss.isEmpty => ddef.name } for i <- List.range(0, arity) @@ -617,8 +644,12 @@ object desugar { cpy.ValDef(vparam)(rhs = copyDefault(vparam))) val copyRestParamss = derivedVparamss.tail.nestedMap(vparam => cpy.ValDef(vparam)(rhs = EmptyTree)) - DefDef(nme.copy, derivedTparams, copyFirstParams :: copyRestParamss, TypeTree(), creatorExpr) - .withMods(Modifiers(Synthetic | constr1.mods.flags & copiedAccessFlags, constr1.mods.privateWithin)) :: Nil + DefDef( + nme.copy, + joinParams(derivedTparams, copyFirstParams :: copyRestParamss), + TypeTree(), + creatorExpr + ).withMods(Modifiers(Synthetic | constr1.mods.flags & copiedAccessFlags, constr1.mods.privateWithin)) :: Nil } } @@ -688,7 +719,7 @@ object desugar { val appParamss = derivedVparamss.nestedZipWithConserve(constrVparamss)((ap, cp) => ap.withMods(ap.mods | (cp.mods.flags & HasDefault))) - DefDef(nme.apply, derivedTparams, appParamss, TypeTree(), creatorExpr) + DefDef(nme.apply, joinParams(derivedTparams, appParamss), TypeTree(), creatorExpr) .withMods(appMods) :: Nil } val unapplyMeth = { @@ -699,11 +730,15 @@ object desugar { val unapplyParam = makeSyntheticParameter(tpt = classTypeRef) val unapplyRHS = if (arity == 0) Literal(Constant(true)) else Ident(unapplyParam.name) val unapplyResTp = if (arity == 0) Literal(Constant(true)) else TypeTree() - DefDef(methName, derivedTparams, (unapplyParam :: Nil) :: Nil, unapplyResTp, unapplyRHS) - .withMods(synthetic) + DefDef( + methName, + joinParams(derivedTparams, (unapplyParam :: Nil) :: Nil), + unapplyResTp, + unapplyRHS + ).withMods(synthetic) } val toStringMeth = - DefDef(nme.toString_, Nil, Nil, TypeTree(), Literal(Constant(className.toString))).withMods(Modifiers(Override | Synthetic)) + DefDef(nme.toString_, Nil, TypeTree(), Literal(Constant(className.toString))).withMods(Modifiers(Override | Synthetic)) companionDefs(anyRef, applyMeths ::: unapplyMeth :: toStringMeth :: companionMembers) } @@ -751,7 +786,9 @@ object desugar { } // implicit wrapper is typechecked in same scope as constructor, so // we can reuse the constructor parameters; no derived params are needed. - DefDef(className.toTermName, constrTparams, defParamss, classTypeRef, creatorExpr) + DefDef( + className.toTermName, joinParams(constrTparams, defParamss), + classTypeRef, creatorExpr) .withMods(companionMods | mods.flags.toTermFlags & GivenOrImplicit | Synthetic | Final) .withSpan(cdef.span) :: Nil } @@ -869,18 +906,24 @@ object desugar { /** Transform extension construct to list of extension methods */ def extMethods(ext: ExtMethods)(using Context): Tree = flatTree { for mdef <- ext.methods yield - if mdef.tparams.nonEmpty then - report.error("extension method cannot have type parameters here, all type parameters go after `extension`", - mdef.tparams.head.srcPos) defDef( cpy.DefDef(mdef)( name = normalizeName(mdef, ext).asTermName, - tparams = ext.tparams ++ mdef.tparams, - vparamss = mdef.vparamss match - case vparams1 :: vparamss1 if mdef.name.isRightAssocOperatorName => - vparams1 :: ext.vparamss ::: vparamss1 + paramss = mdef.paramss match + case params1 :: paramss1 if mdef.name.isRightAssocOperatorName => + def badRightAssoc(problem: String) = + report.error(i"right-associative extension method $problem", mdef.srcPos) + ext.paramss ++ mdef.paramss + params1 match + case ValDefs(vparam :: Nil) => + if !vparam.mods.is(Given) then + val (leadingUsing, otherExtParamss) = ext.paramss.span(isUsingOrTypeParamClause) + leadingUsing ::: params1 :: otherExtParamss ::: paramss1 + else badRightAssoc("cannot start with using clause") + case _ => + badRightAssoc("must start with a single parameter") case _ => - ext.vparamss ++ mdef.vparamss + ext.paramss ++ mdef.paramss ).withMods(mdef.mods | ExtensionMethod) ) } @@ -1262,7 +1305,7 @@ object desugar { */ def makeClosure(params: List[ValDef], body: Tree, tpt: Tree = null, isContextual: Boolean)(using Context): Block = Block( - DefDef(nme.ANON_FUN, Nil, params :: Nil, if (tpt == null) TypeTree() else tpt, body) + DefDef(nme.ANON_FUN, params :: Nil, if (tpt == null) TypeTree() else tpt, body) .withMods(synthetic | Artifact), Closure(Nil, Ident(nme.ANON_FUN), if (isContextual) ContextualEmptyTree else EmptyTree)) @@ -1314,7 +1357,7 @@ object desugar { val vdefs = params.zipWithIndex.map { case (param, idx) => - DefDef(param.name, Nil, Nil, param.tpt, selector(idx)).withSpan(param.span) + DefDef(param.name, Nil, param.tpt, selector(idx)).withSpan(param.span) } Function(param :: Nil, Block(vdefs, body)) } @@ -1357,7 +1400,7 @@ object desugar { } private def derivedDefDef(original: Tree, named: NameTree, tpt: Tree, rhs: Tree, mods: Modifiers)(implicit src: SourceFile) = - DefDef(named.name.asTermName, Nil, Nil, tpt, rhs) + DefDef(named.name.asTermName, Nil, tpt, rhs) .withMods(mods) .withSpan(original.span.withPoint(named.span.start)) @@ -1554,6 +1597,7 @@ object desugar { case Parens(body1) => makePolyFunction(targs, body1) case Function(vargs, res) => + assert(targs.nonEmpty) // TODO: Figure out if we need a `PolyFunctionWithMods` instead. val mods = body match { case body: FunctionWithMods => body.mods @@ -1570,7 +1614,7 @@ object desugar { case (p, n) => makeSyntheticParameter(n + 1, p).withAddedFlags(mods.flags) } RefinedTypeTree(polyFunctionTpt, List( - DefDef(nme.apply, applyTParams, List(applyVParams), res, EmptyTree) + DefDef(nme.apply, applyTParams :: applyVParams :: Nil, res, EmptyTree) )) } else { @@ -1580,7 +1624,7 @@ object desugar { val applyVParams = vargs.asInstanceOf[List[ValDef]] .map(varg => varg.withAddedFlags(mods.flags | Param)) New(Template(emptyConstructor, List(polyFunctionTpt), Nil, EmptyValDef, - List(DefDef(nme.apply, applyTParams, List(applyVParams), TypeTree(), res)) + List(DefDef(nme.apply, applyTParams :: applyVParams :: Nil, TypeTree(), res)) )) } case _ => diff --git a/compiler/src/dotty/tools/dotc/ast/DesugarEnums.scala b/compiler/src/dotty/tools/dotc/ast/DesugarEnums.scala index 41888539900f..d6d92c3fb078 100644 --- a/compiler/src/dotty/tools/dotc/ast/DesugarEnums.scala +++ b/compiler/src/dotty/tools/dotc/ast/DesugarEnums.scala @@ -130,7 +130,7 @@ object DesugarEnums { .withFlags(Private | Synthetic) val valuesDef = - DefDef(nme.values, Nil, Nil, defn.ArrayType.ofRawEnum, valuesDot(nme.clone_)) + DefDef(nme.values, Nil, defn.ArrayType.ofRawEnum, valuesDot(nme.clone_)) .withFlags(Synthetic) val valuesOfBody: Tree = @@ -142,7 +142,7 @@ object DesugarEnums { CaseDef(Literal(Constant(enumValue.name.toString)), EmptyTree, enumValue) ) ::: defaultCase :: Nil Match(Ident(nme.nameDollar), stringCases) - val valueOfDef = DefDef(nme.valueOf, Nil, List(param(nme.nameDollar, defn.StringType) :: Nil), + val valueOfDef = DefDef(nme.valueOf, List(param(nme.nameDollar, defn.StringType) :: Nil), TypeTree(), valuesOfBody) .withFlags(Synthetic) @@ -195,7 +195,7 @@ object DesugarEnums { self = EmptyValDef, body = fieldMethods ).withAttachment(ExtendsSingletonMirror, ())) - DefDef(nme.DOLLAR_NEW, Nil, + DefDef(nme.DOLLAR_NEW, List(List(param(nme.ordinalDollar_, defn.IntType), param(nme.nameDollar, defn.StringType))), TypeTree(), creator).withFlags(Private | Synthetic) } @@ -281,13 +281,13 @@ object DesugarEnums { private def isJavaEnum(using Context): Boolean = enumClass.derivesFrom(defn.JavaEnumClass) def ordinalMeth(body: Tree)(using Context): DefDef = - DefDef(nme.ordinal, Nil, Nil, TypeTree(defn.IntType), body).withAddedFlags(Synthetic) + DefDef(nme.ordinal, Nil, TypeTree(defn.IntType), body).withAddedFlags(Synthetic) def ordinalMethLit(ord: Int)(using Context): DefDef = ordinalMeth(Literal(Constant(ord))) def fromOrdinalMeth(body: Tree => Tree)(using Context): DefDef = - DefDef(nme.fromOrdinal, Nil, (param(nme.ordinal, defn.IntType) :: Nil) :: Nil, + DefDef(nme.fromOrdinal, (param(nme.ordinal, defn.IntType) :: Nil) :: Nil, rawRef(enumClass.typeRef), body(Ident(nme.ordinal))).withFlags(Synthetic) /** Expand a module definition representing a parameterless enum case */ diff --git a/compiler/src/dotty/tools/dotc/ast/MainProxies.scala b/compiler/src/dotty/tools/dotc/ast/MainProxies.scala index 9facdc08eff7..45364481a319 100644 --- a/compiler/src/dotty/tools/dotc/ast/MainProxies.scala +++ b/compiler/src/dotty/tools/dotc/ast/MainProxies.scala @@ -102,7 +102,7 @@ object MainProxies { val body = Try(call, handler :: Nil, EmptyTree) val mainArg = ValDef(nme.args, TypeTree(defn.ArrayType.appliedTo(defn.StringType)), EmptyTree) .withFlags(Param) - val mainMeth = DefDef(nme.main, Nil, (mainArg :: Nil) :: Nil, TypeTree(defn.UnitType), body) + val mainMeth = DefDef(nme.main, (mainArg :: Nil) :: Nil, TypeTree(defn.UnitType), body) .withFlags(JavaStatic) val mainTempl = Template(emptyConstructor, Nil, Nil, EmptyValDef, mainMeth :: Nil) val mainCls = TypeDef(mainFun.name.toTypeName, mainTempl) diff --git a/compiler/src/dotty/tools/dotc/ast/Positioned.scala b/compiler/src/dotty/tools/dotc/ast/Positioned.scala index 47dbd1826d4c..0c1f43b8f292 100644 --- a/compiler/src/dotty/tools/dotc/ast/Positioned.scala +++ b/compiler/src/dotty/tools/dotc/ast/Positioned.scala @@ -206,20 +206,15 @@ abstract class Positioned(implicit @constructorOnly src: SourceFile) extends Src this match { case tree: DefDef if tree.name == nme.CONSTRUCTOR && tree.mods.is(JavaDefined) => // Special treatment for constructors coming from Java: - // Leave out tparams, they are copied with wrong positions from parent class + // Leave out leading type params, they are copied with wrong positions from parent class check(tree.mods) - check(tree.vparamss) + check(tree.trailingParamss) case tree: DefDef if tree.mods.is(ExtensionMethod) => - tree.vparamss match { + tree.paramss match case vparams1 :: vparams2 :: rest if tree.name.isRightAssocOperatorName => - check(tree.tparams) - check(vparams2) - check(vparams1) - check(rest) + // omit check for right-associatiove extension methods; their parameters were swapped case _ => - check(tree.tparams) - check(tree.vparamss) - } + check(tree.paramss) check(tree.tpt) check(tree.rhs) case _ => diff --git a/compiler/src/dotty/tools/dotc/ast/TreeInfo.scala b/compiler/src/dotty/tools/dotc/ast/TreeInfo.scala index f29bde70744d..62ab6d2ba844 100644 --- a/compiler/src/dotty/tools/dotc/ast/TreeInfo.scala +++ b/compiler/src/dotty/tools/dotc/ast/TreeInfo.scala @@ -22,7 +22,7 @@ trait TreeInfo[T >: Untyped <: Type] { self: Trees.Instance[T] => def unsplice(tree: Trees.Tree[T]): Trees.Tree[T] = tree def isDeclarationOrTypeDef(tree: Tree): Boolean = unsplice(tree) match { - case DefDef(_, _, _, _, EmptyTree) + case DefDef(_, _, _, EmptyTree) | ValDef(_, _, EmptyTree) | TypeDef(_, _) => true case _ => false @@ -171,12 +171,6 @@ trait TreeInfo[T >: Untyped <: Type] { self: Trees.Instance[T] => case nil => EmptyTree } - /** The arguments to the first constructor in `stats`. */ - def firstConstructorArgs(stats: List[Tree]): List[Tree] = firstConstructor(stats) match { - case DefDef(_, _, args :: _, _, _) => args - case _ => Nil - } - /** Is tpt a vararg type of the form T* or => T*? */ def isRepeatedParamType(tpt: Tree)(using Context): Boolean = tpt match { case ByNameTypeTree(tpt1) => isRepeatedParamType(tpt1) @@ -198,7 +192,7 @@ trait TreeInfo[T >: Untyped <: Type] { self: Trees.Instance[T] => /** All type and value parameter symbols of this DefDef */ def allParamSyms(ddef: DefDef)(using Context): List[Symbol] = - (ddef.tparams ::: ddef.vparamss.flatten).map(_.symbol) + ddef.paramss.flatten.map(_.symbol) /** Does this argument list end with an argument of the form : _* ? */ def isWildcardStarArgList(trees: List[Tree])(using Context): Boolean = @@ -245,6 +239,18 @@ trait TreeInfo[T >: Untyped <: Type] { self: Trees.Instance[T] => /** Is this case guarded? */ def isGuardedCase(cdef: CaseDef): Boolean = cdef.guard ne EmptyTree + /** Is this parameter list a using clause? */ + def isUsingClause(params: ParamClause)(using Context): Boolean = params match + case ValDefs(vparam :: _) => + val sym = vparam.symbol + if sym.exists then sym.is(Given) else vparam.mods.is(Given) + case _ => + false + + def isUsingOrTypeParamClause(params: ParamClause)(using Context): Boolean = params match + case TypeDefs(_) => true + case _ => isUsingClause(params) + /** The underlying pattern ignoring any bindings */ def unbind(x: Tree): Tree = unsplice(x) match { case Bind(_, y) => unbind(y) @@ -305,11 +311,11 @@ trait UntypedTreeInfo extends TreeInfo[Untyped] { self: Trees.Instance[Untyped] case Function((param: untpd.ValDef) :: _, _) => param.mods.is(Given) case Closure(_, meth, _) => true case Block(Nil, expr) => isContextualClosure(expr) - case Block(DefDef(nme.ANON_FUN, _, params :: _, _, _) :: Nil, cl: Closure) => - params match { - case param :: _ => param.mods.is(Given) - case Nil => cl.tpt.eq(untpd.ContextualEmptyTree) || defn.isContextFunctionType(cl.tpt.typeOpt) - } + case Block(DefDef(nme.ANON_FUN, params :: _, _, _) :: Nil, cl: Closure) => + if params.isEmpty then + cl.tpt.eq(untpd.ContextualEmptyTree) || defn.isContextFunctionType(cl.tpt.typeOpt) + else + isUsingClause(params) case _ => false } @@ -320,11 +326,17 @@ trait UntypedTreeInfo extends TreeInfo[Untyped] { self: Trees.Instance[Untyped] case EmptyTree | _: Import => NoInitsInterface case tree: TypeDef => if (tree.isClassDef) NoInits else NoInitsInterface case tree: DefDef => - if (tree.unforcedRhs == EmptyTree && - tree.vparamss.forall(_.forall(_.rhs.isEmpty))) NoInitsInterface - else if (tree.mods.is(Given) && tree.tparams.isEmpty && tree.vparamss.isEmpty) + if tree.unforcedRhs == EmptyTree + && tree.paramss.forall { + case ValDefs(vparams) => vparams.forall(_.rhs.isEmpty) + case _ => true + } + then + NoInitsInterface + else if tree.mods.is(Given) && tree.paramss.isEmpty then EmptyFlags // might become a lazy val: TODO: check whether we need to suppress NoInits once we have new lazy val impl - else NoInits + else + NoInits case tree: ValDef => if (tree.unforcedRhs == EmptyTree) NoInitsInterface else EmptyFlags case _ => EmptyFlags } @@ -346,8 +358,6 @@ trait UntypedTreeInfo extends TreeInfo[Untyped] { self: Trees.Instance[Untyped] case _ => None } } - - // todo: fill with other methods from TreeInfo that only apply to untpd.Tree's } trait TypedTreeInfo extends TreeInfo[Type] { self: Trees.Instance[Type] => @@ -363,7 +373,7 @@ trait TypedTreeInfo extends TreeInfo[Type] { self: Trees.Instance[Type] => case EmptyTree | TypeDef(_, _) | Import(_, _) - | DefDef(_, _, _, _, _) => + | DefDef(_, _, _, _) => Pure case vdef @ ValDef(_, _, _) => if (vdef.symbol.flags is Mutable) Impure else exprPurity(vdef.rhs) `min` Pure @@ -554,6 +564,11 @@ trait TypedTreeInfo extends TreeInfo[Type] { self: Trees.Instance[Type] => } } + def isExtMethodApply(tree: Tree)(using Context): Boolean = methPart(tree) match + case Inlined(call, _, _) => isExtMethodApply(call) + case tree @ Select(qual, nme.apply) => tree.symbol.is(ExtensionMethod) || isExtMethodApply(qual) + case tree => tree.symbol.is(ExtensionMethod) + /** Is symbol potentially a getter of a mutable variable? */ def mayBeVarGetter(sym: Symbol)(using Context): Boolean = { @@ -606,24 +621,38 @@ trait TypedTreeInfo extends TreeInfo[Type] { self: Trees.Instance[Type] => } } - /** Decompose a call fn[targs](vargs_1)...(vargs_n) - * into its constituents (fn, targs, vargss). - * - * Note: targ and vargss may be empty - */ - def decomposeCall(tree: Tree): (Tree, List[Tree], List[List[Tree]]) = { + /** The type arguemnts of a possibly curried call */ + def typeArgss(tree: Tree): List[List[Tree]] = @tailrec - def loop(tree: Tree, targss: List[Tree], argss: List[List[Tree]]): (Tree, List[Tree], List[List[Tree]]) = - tree match { - case Apply(fn, args) => - loop(fn, targss, args :: argss) - case TypeApply(fn, targs) => - loop(fn, targs ::: targss, argss) - case _ => - (tree, targss, argss) - } - loop(tree, Nil, Nil) - } + def loop(tree: Tree, argss: List[List[Tree]]): List[List[Tree]] = tree match + case TypeApply(fn, args) => loop(fn, args :: argss) + case Apply(fn, args) => loop(fn, argss) + case _ => argss + loop(tree, Nil) + + /** The term arguemnts of a possibly curried call */ + def termArgss(tree: Tree): List[List[Tree]] = + @tailrec + def loop(tree: Tree, argss: List[List[Tree]]): List[List[Tree]] = tree match + case Apply(fn, args) => loop(fn, args :: argss) + case TypeApply(fn, args) => loop(fn, argss) + case _ => argss + loop(tree, Nil) + + /** The type and term arguemnts of a possibly curried call, in the order they are given */ + def allArgss(tree: Tree): List[List[Tree]] = + @tailrec + def loop(tree: Tree, argss: List[List[Tree]]): List[List[Tree]] = tree match + case tree: GenericApply => loop(tree.fun, tree.args :: argss) + case _ => argss + loop(tree, Nil) + + /** The function part of a possibly curried call. Unlike `methPart` this one does + * not decompose blocks + */ + def funPart(tree: Tree): Tree = tree match + case tree: GenericApply => funPart(tree.fun) + case tree => tree /** Decompose a template body into parameters and other statements */ def decomposeTemplateBody(body: List[Tree])(using Context): (List[Tree], List[Tree]) = @@ -886,7 +915,7 @@ trait TypedTreeInfo extends TreeInfo[Type] { self: Trees.Instance[Type] => * will return a term or type tree respectively. */ def unapply(tree: tpd.Tree)(using Context): Option[tpd.Tree] = tree match { - case tree: GenericApply[Type] if tree.symbol.isQuote => Some(tree.args.head) + case tree: GenericApply if tree.symbol.isQuote => Some(tree.args.head) case _ => None } } diff --git a/compiler/src/dotty/tools/dotc/ast/TreeMapWithImplicits.scala b/compiler/src/dotty/tools/dotc/ast/TreeMapWithImplicits.scala index 2dac4ab70f37..98376c497868 100644 --- a/compiler/src/dotty/tools/dotc/ast/TreeMapWithImplicits.scala +++ b/compiler/src/dotty/tools/dotc/ast/TreeMapWithImplicits.scala @@ -94,10 +94,9 @@ class TreeMapWithImplicits extends tpd.TreeMap { inContext(localCtx) { cpy.DefDef(tree)( tree.name, - transformSub(tree.tparams), - tree.vparamss mapConserve (transformSub(_)), + transformParamss(tree.paramss), transform(tree.tpt), - transform(tree.rhs)(using nestedScopeCtx(tree.vparamss.flatten))) + transform(tree.rhs)(using nestedScopeCtx(tree.paramss.flatten))) } case EmptyValDef => tree diff --git a/compiler/src/dotty/tools/dotc/ast/TreeTypeMap.scala b/compiler/src/dotty/tools/dotc/ast/TreeTypeMap.scala index 1d98d643ad89..fddde05d9a31 100644 --- a/compiler/src/dotty/tools/dotc/ast/TreeTypeMap.scala +++ b/compiler/src/dotty/tools/dotc/ast/TreeTypeMap.scala @@ -90,11 +90,10 @@ class TreeTypeMap( tree1.withType(mapType(tree1.tpe)) match { case id: Ident if tpd.needsSelect(id.tpe) => ref(id.tpe.asInstanceOf[TermRef]).withSpan(id.span) - case ddef @ DefDef(name, tparams, vparamss, tpt, _) => - val (tmap1, tparams1) = transformDefs(tparams) - val (tmap2, vparamss1) = tmap1.transformVParamss(vparamss) - val res = cpy.DefDef(ddef)(name, tparams1, vparamss1, tmap2.transform(tpt), tmap2.transform(ddef.rhs)) - res.symbol.setParamssFromDefs(tparams1, vparamss1) + case ddef @ DefDef(name, paramss, tpt, _) => + val (tmap1, paramss1) = transformAllParamss(paramss) + val res = cpy.DefDef(ddef)(name, paramss1, tmap1.transform(tpt), tmap1.transform(ddef.rhs)) + res.symbol.setParamssFromDefs(paramss1) res.symbol.transformAnnotations { case ann: BodyAnnotation => ann.derivedAnnotation(transform(ann.tree)) case ann => ann @@ -139,14 +138,15 @@ class TreeTypeMap( (tmap, tmap.transformSub(trees)) } - private def transformVParamss(vparamss: List[List[ValDef]]): (TreeTypeMap, List[List[ValDef]]) = vparamss match { - case vparams :: rest => - val (tmap1, vparams1) = transformDefs(vparams) - val (tmap2, vparamss2) = tmap1.transformVParamss(rest) - (tmap2, vparams1 :: vparamss2) + private def transformAllParamss(paramss: List[ParamClause]): (TreeTypeMap, List[ParamClause]) = paramss match + case params :: paramss1 => + val (tmap1, params1: ParamClause) = (params: @unchecked) match + case ValDefs(vparams) => transformDefs(vparams) + case TypeDefs(tparams) => transformDefs(tparams) + val (tmap2, paramss2) = tmap1.transformAllParamss(paramss1) + (tmap2, params1 :: paramss2) case nil => - (this, vparamss) - } + (this, paramss) def apply[ThisTree <: tpd.Tree](tree: ThisTree): ThisTree = transform(tree).asInstanceOf[ThisTree] diff --git a/compiler/src/dotty/tools/dotc/ast/Trees.scala b/compiler/src/dotty/tools/dotc/ast/Trees.scala index 7064ccc2e2c2..cde5acb2211a 100644 --- a/compiler/src/dotty/tools/dotc/ast/Trees.scala +++ b/compiler/src/dotty/tools/dotc/ast/Trees.scala @@ -382,6 +382,11 @@ object Trees { def rhs(using Context): Tree[T] = forceIfLazy } + trait ValOrTypeDef[-T >: Untyped] extends MemberDef[T]: + type ThisTree[-T >: Untyped] <: ValOrTypeDef[T] + + type ParamClause[T >: Untyped] = List[ValDef[T]] | List[TypeDef[T]] + // ----------- Tree case classes ------------------------------------ /** name */ @@ -743,7 +748,7 @@ object Trees { /** mods val name: tpt = rhs */ case class ValDef[-T >: Untyped] private[ast] (name: TermName, tpt: Tree[T], private var preRhs: LazyTree[T @uncheckedVariance])(implicit @constructorOnly src: SourceFile) - extends ValOrDefDef[T] { + extends ValOrDefDef[T], ValOrTypeDef[T] { type ThisTree[-T >: Untyped] = ValDef[T] assert(isEmpty || tpt != genericEmptyTree) def unforced: LazyTree[T] = preRhs @@ -751,13 +756,25 @@ object Trees { } /** mods def name[tparams](vparams_1)...(vparams_n): tpt = rhs */ - case class DefDef[-T >: Untyped] private[ast] (name: TermName, tparams: List[TypeDef[T]], - vparamss: List[List[ValDef[T]]], tpt: Tree[T], private var preRhs: LazyTree[T @uncheckedVariance])(implicit @constructorOnly src: SourceFile) + case class DefDef[-T >: Untyped] private[ast] (name: TermName, + paramss: List[ParamClause[T]], tpt: Tree[T], private var preRhs: LazyTree[T @uncheckedVariance])(implicit @constructorOnly src: SourceFile) extends ValOrDefDef[T] { type ThisTree[-T >: Untyped] = DefDef[T] assert(tpt != genericEmptyTree) def unforced: LazyTree[T] = preRhs protected def force(x: Tree[T @uncheckedVariance]): Unit = preRhs = x + + def leadingTypeParams(using Context): List[TypeDef[T]] = paramss match + case (tparams @ (tparam: TypeDef[_]) :: _) :: _ => tparams.asInstanceOf[List[TypeDef[T]]] + case _ => Nil + + def trailingParamss(using Context): List[ParamClause[T]] = paramss match + case ((tparam: TypeDef[_]) :: _) :: paramss1 => paramss1 + case _ => paramss + + def termParamss(using Context): List[List[ValDef[T]]] = + (if ctx.erasedTypes then paramss else untpd.termParamssIn(paramss)) + .asInstanceOf[List[List[ValDef[T]]]] } /** mods class name template or @@ -767,7 +784,7 @@ object Trees { * mods type name >: lo <: hi = rhs if rhs = TypeBoundsTree(lo, hi, alias) and opaque in mods */ case class TypeDef[-T >: Untyped] private[ast] (name: TypeName, rhs: Tree[T])(implicit @constructorOnly src: SourceFile) - extends MemberDef[T] { + extends MemberDef[T], ValOrTypeDef[T] { type ThisTree[-T >: Untyped] = TypeDef[T] /** Is this a definition of a class? */ @@ -959,8 +976,10 @@ object Trees { type NamedDefTree = Trees.NamedDefTree[T] type MemberDef = Trees.MemberDef[T] type ValOrDefDef = Trees.ValOrDefDef[T] + type ValOrTypeDef = Trees.ValOrTypeDef[T] type LazyTree = Trees.LazyTree[T] type LazyTreeList = Trees.LazyTreeList[T] + type ParamClause = Trees.ParamClause[T] type Ident = Trees.Ident[T] type SearchFailureIdent = Trees.SearchFailureIdent[T] @@ -970,6 +989,7 @@ object Trees { type Super = Trees.Super[T] type Apply = Trees.Apply[T] type TypeApply = Trees.TypeApply[T] + type GenericApply = Trees.GenericApply[T] type Literal = Trees.Literal[T] type New = Trees.New[T] type Typed = Trees.Typed[T] @@ -1203,9 +1223,9 @@ object Trees { case tree: ValDef if (name == tree.name) && (tpt eq tree.tpt) && (rhs eq tree.unforcedRhs) => tree case _ => finalize(tree, untpd.ValDef(name, tpt, rhs)(sourceFile(tree))) } - def DefDef(tree: Tree)(name: TermName, tparams: List[TypeDef], vparamss: List[List[ValDef]], tpt: Tree, rhs: LazyTree)(using Context): DefDef = tree match { - case tree: DefDef if (name == tree.name) && (tparams eq tree.tparams) && (vparamss eq tree.vparamss) && (tpt eq tree.tpt) && (rhs eq tree.unforcedRhs) => tree - case _ => finalize(tree, untpd.DefDef(name, tparams, vparamss, tpt, rhs)(sourceFile(tree))) + def DefDef(tree: Tree)(name: TermName, paramss: List[ParamClause], tpt: Tree, rhs: LazyTree)(using Context): DefDef = tree match { + case tree: DefDef if (name == tree.name) && (paramss eq tree.paramss) && (tpt eq tree.tpt) && (rhs eq tree.unforcedRhs) => tree + case _ => finalize(tree, untpd.DefDef(name, paramss, tpt, rhs)(sourceFile(tree))) } def TypeDef(tree: Tree)(name: TypeName, rhs: Tree)(using Context): TypeDef = tree match { case tree: TypeDef if (name == tree.name) && (rhs eq tree.rhs) => tree @@ -1250,8 +1270,8 @@ object Trees { UnApply(tree: Tree)(fun, implicits, patterns) def ValDef(tree: ValDef)(name: TermName = tree.name, tpt: Tree = tree.tpt, rhs: LazyTree = tree.unforcedRhs)(using Context): ValDef = ValDef(tree: Tree)(name, tpt, rhs) - def DefDef(tree: DefDef)(name: TermName = tree.name, tparams: List[TypeDef] = tree.tparams, vparamss: List[List[ValDef]] = tree.vparamss, tpt: Tree = tree.tpt, rhs: LazyTree = tree.unforcedRhs)(using Context): DefDef = - DefDef(tree: Tree)(name, tparams, vparamss, tpt, rhs) + def DefDef(tree: DefDef)(name: TermName = tree.name, paramss: List[ParamClause] = tree.paramss, tpt: Tree = tree.tpt, rhs: LazyTree = tree.unforcedRhs)(using Context): DefDef = + DefDef(tree: Tree)(name, paramss, tpt, rhs) def TypeDef(tree: TypeDef)(name: TypeName = tree.name, rhs: Tree = tree.rhs)(using Context): TypeDef = TypeDef(tree: Tree)(name, rhs) def Template(tree: Template)(constr: DefDef = tree.constr, parents: List[Tree] = tree.parents, derived: List[untpd.Tree] = tree.derived, self: ValDef = tree.self, body: LazyTreeList = tree.unforcedBody)(using Context): Template = @@ -1361,9 +1381,9 @@ object Trees { val rhs1 = transform(tree.rhs) cpy.ValDef(tree)(name, tpt1, rhs1) } - case tree @ DefDef(name, tparams, vparamss, tpt, _) => + case tree @ DefDef(name, paramss, tpt, _) => inContext(localCtx) { - cpy.DefDef(tree)(name, transformSub(tparams), vparamss mapConserve (transformSub(_)), transform(tpt), transform(tree.rhs)) + cpy.DefDef(tree)(name, transformParamss(paramss), transform(tpt), transform(tree.rhs)) } case tree @ TypeDef(name, rhs) => inContext(localCtx) { @@ -1396,6 +1416,10 @@ object Trees { transform(tree).asInstanceOf[Tr] def transformSub[Tr <: Tree](trees: List[Tr])(using Context): List[Tr] = transform(trees).asInstanceOf[List[Tr]] + def transformParams(params: ParamClause)(using Context): ParamClause = + transform(params).asInstanceOf[ParamClause] + def transformParamss(paramss: List[ParamClause])(using Context): List[ParamClause] = + paramss.mapConserve(transformParams) protected def transformMoreCases(tree: Tree)(using Context): Tree = { assert(ctx.reporter.errorsReported) @@ -1497,9 +1521,9 @@ object Trees { inContext(localCtx) { this(this(x, tpt), tree.rhs) } - case tree @ DefDef(_, tparams, vparamss, tpt, _) => + case tree @ DefDef(_, paramss, tpt, _) => inContext(localCtx) { - this(this(vparamss.foldLeft(this(x, tparams))(apply), tpt), tree.rhs) + this(this(paramss.foldLeft(x)(apply), tpt), tree.rhs) } case TypeDef(_, rhs) => inContext(localCtx) { @@ -1567,6 +1591,47 @@ object Trees { } }.asInstanceOf[tree.ThisTree[T]] + object TypeDefs: + def unapply(xs: List[Tree]): Option[List[TypeDef]] = xs match + case (x: TypeDef) :: _ => Some(xs.asInstanceOf[List[TypeDef]]) + case _ => None + + object ValDefs: + def unapply(xs: List[Tree]): Option[List[ValDef]] = xs match + case Nil => Some(Nil) + case (x: ValDef) :: _ => Some(xs.asInstanceOf[List[ValDef]]) + case _ => None + + def termParamssIn(paramss: List[ParamClause]): List[List[ValDef]] = paramss match + case ValDefs(vparams) :: paramss1 => + val paramss2 = termParamssIn(paramss1) + if paramss2 eq paramss1 then paramss.asInstanceOf[List[List[ValDef]]] + else vparams :: paramss2 + case _ :: paramss1 => + termParamssIn(paramss1) + case nil => + Nil + + /** If `tparams` is non-empty, add it to the left `paramss`, merging + * it with a leading type parameter list of `paramss`, if one exists. + */ + def joinParams(tparams: List[TypeDef], paramss: List[ParamClause]): List[ParamClause] = + if tparams.isEmpty then paramss + else paramss match + case TypeDefs(tparams1) :: paramss1 => (tparams ++ tparams1) :: paramss1 + case _ => tparams :: paramss + + def isTermOnly(paramss: List[ParamClause]): Boolean = paramss match + case Nil => true + case params :: paramss1 => + params match + case (param: untpd.TypeDef) :: _ => false + case _ => isTermOnly(paramss1) + + def asTermOnly(paramss: List[ParamClause]): List[List[ValDef]] = + assert(isTermOnly(paramss)) + paramss.asInstanceOf[List[List[ValDef]]] + /** Delegate to FunProto or FunProtoTyped depending on whether the prefix is `untpd` or `tpd`. */ protected def FunProto(args: List[Tree], resType: Type)(using Context): ProtoTypes.FunProto diff --git a/compiler/src/dotty/tools/dotc/ast/tpd.scala b/compiler/src/dotty/tools/dotc/ast/tpd.scala index c14238b06c06..e074efe035ee 100644 --- a/compiler/src/dotty/tools/dotc/ast/tpd.scala +++ b/compiler/src/dotty/tools/dotc/ast/tpd.scala @@ -42,12 +42,12 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo { Super(qual, if (mixName.isEmpty) untpd.EmptyTypeIdent else untpd.Ident(mixName), mixinClass) def Apply(fn: Tree, args: List[Tree])(using Context): Apply = { - assert(fn.isInstanceOf[RefTree] || fn.isInstanceOf[GenericApply[_]] || fn.isInstanceOf[Inlined] || fn.isInstanceOf[tasty.TreePickler.Hole]) + assert(fn.isInstanceOf[RefTree] || fn.isInstanceOf[GenericApply] || fn.isInstanceOf[Inlined] || fn.isInstanceOf[tasty.TreePickler.Hole]) ta.assignType(untpd.Apply(fn, args), fn, args) } def TypeApply(fn: Tree, args: List[Tree])(using Context): TypeApply = { - assert(fn.isInstanceOf[RefTree] || fn.isInstanceOf[GenericApply[_]]) + assert(fn.isInstanceOf[RefTree] || fn.isInstanceOf[GenericApply]) ta.assignType(untpd.TypeApply(fn, args), fn, args) } @@ -196,7 +196,7 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo { ta.assignType(untpd.Alternative(trees), trees) def UnApply(fun: Tree, implicits: List[Tree], patterns: List[Tree], proto: Type)(using Context): UnApply = { - assert(fun.isInstanceOf[RefTree] || fun.isInstanceOf[GenericApply[_]]) + assert(fun.isInstanceOf[RefTree] || fun.isInstanceOf[GenericApply]) ta.assignType(untpd.UnApply(fun, implicits, patterns), proto) } @@ -206,14 +206,17 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo { def SyntheticValDef(name: TermName, rhs: Tree)(using Context): ValDef = ValDef(newSymbol(ctx.owner, name, Synthetic, rhs.tpe.widen, coord = rhs.span), rhs) - def DefDef(sym: TermSymbol, tparams: List[TypeSymbol], vparamss: List[List[TermSymbol]], + def DefDef(sym: TermSymbol, paramss: List[List[Symbol]], resultType: Type, rhs: Tree)(using Context): DefDef = - sym.setParamss(tparams, vparamss) + sym.setParamss(paramss) ta.assignType( untpd.DefDef( sym.name, - tparams.map(tparam => TypeDef(tparam).withSpan(tparam.span)), - vparamss.nestedMap(vparam => ValDef(vparam).withSpan(vparam.span)), + paramss.map { + case TypeSymbols(params) => params.map(param => TypeDef(param).withSpan(param.span)) + case TermSymbols(params) => params.map(param => ValDef(param).withSpan(param.span)) + case _ => ??? + }, TypeTree(resultType), rhs), sym) @@ -221,71 +224,64 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo { def DefDef(sym: TermSymbol, rhs: Tree = EmptyTree)(using Context): DefDef = ta.assignType(DefDef(sym, Function.const(rhs) _), sym) - def DefDef(sym: TermSymbol, rhsFn: List[List[Tree]] => Tree)(using Context): DefDef = - polyDefDef(sym, Function.const(rhsFn)) - /** A DefDef with given method symbol `sym`. - * @rhsFn A function from type parameter types and term parameter references + * @rhsFn A function from parameter references * to the method's right-hand side. * Parameter symbols are taken from the `rawParamss` field of `sym`, or * are freshly generated if `rawParamss` is empty. */ - def polyDefDef(sym: TermSymbol, rhsFn: List[Type] => List[List[Tree]] => Tree)(using Context): DefDef = { + def DefDef(sym: TermSymbol, rhsFn: List[List[Tree]] => Tree)(using Context): DefDef = - val (tparams, existingParamss, mtp) = sym.info match { + // Map method type `tp` with remaining parameters stored in rawParamss to + // final result type and all (given or synthesized) parameters + def recur(tp: Type, remaining: List[List[Symbol]]): (Type, List[List[Symbol]]) = tp match case tp: PolyType => - val (tparams, existingParamss) = sym.rawParamss match - case tparams :: vparamss => + val (tparams: List[TypeSymbol], remaining1) = remaining match + case tparams :: remaining1 => assert(tparams.hasSameLengthAs(tp.paramNames) && tparams.head.isType) - (tparams.asInstanceOf[List[TypeSymbol]], vparamss) - case _ => + (tparams.asInstanceOf[List[TypeSymbol]], remaining1) + case nil => (newTypeParams(sym, tp.paramNames, EmptyFlags, tp.instantiateParamInfos(_)), Nil) - (tparams, existingParamss, tp.instantiate(tparams map (_.typeRef))) - case tp => (Nil, sym.rawParamss, tp) - } - - def valueParamss(tp: Type, existingParamss: List[List[Symbol]]): (List[List[TermSymbol]], Type) = tp match { + val (rtp, paramss) = recur(tp.instantiate(tparams.map(_.typeRef)), remaining1) + (rtp, tparams :: paramss) case tp: MethodType => val isParamDependent = tp.isParamDependent - val previousParamRefs = if (isParamDependent) mutable.ListBuffer[TermRef]() else null + val previousParamRefs = if isParamDependent then mutable.ListBuffer[TermRef]() else null - def valueParam(name: TermName, origInfo: Type): TermSymbol = { + def valueParam(name: TermName, origInfo: Type): TermSymbol = val maybeImplicit = - if (tp.isContextualMethod) Given - else if (tp.isImplicitMethod) Implicit + if tp.isContextualMethod then Given + else if tp.isImplicitMethod then Implicit else EmptyFlags - val maybeErased = if (tp.isErasedMethod) Erased else EmptyFlags + val maybeErased = if tp.isErasedMethod then Erased else EmptyFlags def makeSym(info: Type) = newSymbol(sym, name, TermParam | maybeImplicit | maybeErased, info, coord = sym.coord) - if (isParamDependent) { + if isParamDependent then val sym = makeSym(origInfo.substParams(tp, previousParamRefs.toList)) previousParamRefs += sym.termRef sym - } - else - makeSym(origInfo) - } + else makeSym(origInfo) + end valueParam - val (params, existingParamss1) = - if tp.paramInfos.isEmpty then (Nil, existingParamss) - else existingParamss match - case vparams :: existingParamss1 => + val (vparams: List[TermSymbol], remaining1) = + if tp.paramNames.isEmpty then (Nil, remaining) + else remaining match + case vparams :: remaining1 => assert(vparams.hasSameLengthAs(tp.paramNames) && vparams.head.isTerm) - (vparams.asInstanceOf[List[TermSymbol]], existingParamss1) - case _ => + (vparams.asInstanceOf[List[TermSymbol]], remaining1) + case nil => (tp.paramNames.lazyZip(tp.paramInfos).map(valueParam), Nil) - val (paramss, rtp) = - valueParamss(tp.instantiate(params map (_.termRef)), existingParamss1) - (params :: paramss, rtp) - case tp => (Nil, tp.widenExpr) - } - val (vparamss, rtp) = valueParamss(mtp, existingParamss) - val targs = tparams map (_.typeRef) - val argss = vparamss.nestedMap(vparam => Ident(vparam.termRef)) - sym.setParamss(tparams, vparamss) - DefDef(sym, tparams, vparamss, rtp, rhsFn(targs)(argss)) - } + val (rtp, paramss) = recur(tp.instantiate(vparams.map(_.termRef)), remaining1) + (rtp, vparams :: paramss) + case _ => + assert(remaining.isEmpty) + (tp.widenExpr, Nil) + end recur + + val (rtp, paramss) = recur(sym.info, sym.rawParamss) + DefDef(sym, paramss, rtp, rhsFn(paramss.nestedMap(ref))) + end DefDef def TypeDef(sym: TypeSymbol)(using Context): TypeDef = ta.assignType(untpd.TypeDef(sym.name, TypeTree(sym.info)), sym) @@ -353,7 +349,7 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo { for overridden <- fwdMeth.allOverriddenSymbols do if overridden.is(Extension) then fwdMeth.setFlag(Extension) if !overridden.is(Deferred) then fwdMeth.setFlag(Override) - polyDefDef(fwdMeth, tprefs => prefss => ref(fn).appliedToTypes(tprefs).appliedToArgss(prefss)) + DefDef(fwdMeth, ref(fn).appliedToArgss(_)) } val forwarders = fns.lazyZip(methNames).map(forwarder) val cdef = ClassDef(cls, DefDef(constr), forwarders) @@ -465,10 +461,10 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo { if (!ctx.erasedTypes) { assert(!TypeErasure.isGeneric(elemTpe), elemTpe) //needs to be done during typer. See Applications.convertNewGenericArray - newArr.appliedToTypeTrees(TypeTree(returnTpe) :: Nil).appliedToArgs(clsOf(elemTpe) :: clsOf(returnTpe) :: dims :: Nil).withSpan(span) + newArr.appliedToTypeTrees(TypeTree(returnTpe) :: Nil).appliedToTermArgs(clsOf(elemTpe) :: clsOf(returnTpe) :: dims :: Nil).withSpan(span) } else // after erasure - newArr.appliedToArgs(clsOf(elemTpe) :: clsOf(returnTpe) :: dims :: Nil).withSpan(span) + newArr.appliedToTermArgs(clsOf(elemTpe) :: clsOf(returnTpe) :: dims :: Nil).withSpan(span) } /** The wrapped array method name for an array of type elemtp */ @@ -502,7 +498,7 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo { New(tycon) .select(TermRef(tycon, constr)) .appliedToTypes(targs) - .appliedToArgs(args) + .appliedToTermArgs(args) } /** An object def @@ -900,28 +896,33 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo { /** A unary apply node with given argument: `tree(arg)` */ def appliedTo(arg: Tree)(using Context): Apply = - appliedToArgs(arg :: Nil) + appliedToTermArgs(arg :: Nil) /** An apply node with given arguments: `tree(arg, args0, ..., argsN)` */ def appliedTo(arg: Tree, args: Tree*)(using Context): Apply = - appliedToArgs(arg :: args.toList) + appliedToTermArgs(arg :: args.toList) /** An apply node with given argument list `tree(args(0), ..., args(args.length - 1))` */ - def appliedToArgs(args: List[Tree])(using Context): Apply = + def appliedToTermArgs(args: List[Tree])(using Context): Apply = Apply(tree, args) /** An applied node that accepts only varargs as arguments */ def appliedToVarargs(args: List[Tree], tpt: Tree)(using Context): Apply = appliedTo(repeated(args, tpt)) - /** The current tree applied to given argument lists: + /** An apply or type apply node with given argument list */ + def appliedToArgs(args: List[Tree])(using Context): GenericApply = args match + case arg :: args1 if arg.isType => TypeApply(tree, args) + case _ => Apply(tree, args) + + /** The current tree applied to given argument lists: * `tree (argss(0)) ... (argss(argss.length -1))` */ def appliedToArgss(argss: List[List[Tree]])(using Context): Tree = - argss.foldLeft(tree: Tree)(Apply(_, _)) + argss.foldLeft(tree: Tree)(_.appliedToArgs(_)) /** The current tree applied to (): `tree()` */ - def appliedToNone(using Context): Apply = appliedToArgs(Nil) + def appliedToNone(using Context): Apply = Apply(tree, Nil) /** The current tree applied to given type argument: `tree[targ]` */ def appliedToType(targ: Type)(using Context): Tree = @@ -1226,15 +1227,27 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo { letBindUnless(TreeInfo.Idempotent, tree)(within) def runtimeCall(name: TermName, args: List[Tree])(using Context): Tree = - Ident(defn.ScalaRuntimeModule.requiredMethod(name).termRef).appliedToArgs(args) + Ident(defn.ScalaRuntimeModule.requiredMethod(name).termRef).appliedToTermArgs(args) /** An extractor that pulls out type arguments */ - object MaybePoly { - def unapply(tree: Tree): Option[(Tree, List[Tree])] = tree match { + object MaybePoly: + def unapply(tree: Tree): Option[(Tree, List[Tree])] = tree match case TypeApply(tree, targs) => Some(tree, targs) case _ => Some(tree, Nil) - } - } + + object TypeArgs: + def unapply(ts: List[Tree]): Option[List[Tree]] = + if ts.nonEmpty && ts.head.isType then Some(ts) else None + + /** Split argument clauses into a leading type argument clause if it exists and + * remaining clauses + */ + def splitArgs(argss: List[List[Tree]]): (List[Tree], List[List[Tree]]) = argss match + case TypeArgs(targs) :: argss1 => (targs, argss1) + case _ => (Nil, argss) + + def joinArgs(targs: List[Tree], argss: List[List[Tree]]): List[List[Tree]] = + if targs.isEmpty then argss else targs :: argss /** A key to be used in a context property that tracks enclosing inlined calls */ private val InlinedCalls = Property.Key[List[Tree]]() diff --git a/compiler/src/dotty/tools/dotc/ast/untpd.scala b/compiler/src/dotty/tools/dotc/ast/untpd.scala index b98d7df11221..2a00e8fd9fd1 100644 --- a/compiler/src/dotty/tools/dotc/ast/untpd.scala +++ b/compiler/src/dotty/tools/dotc/ast/untpd.scala @@ -118,7 +118,7 @@ object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo { case class GenAlias(pat: Tree, expr: Tree)(implicit @constructorOnly src: SourceFile) extends Tree 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(tparams: List[TypeDef], vparamss: List[List[ValDef]], methods: List[DefDef])(implicit @constructorOnly src: SourceFile) extends Tree + case class ExtMethods(paramss: List[ParamClause], methods: List[DefDef])(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 { @@ -402,7 +402,7 @@ object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo { def Alternative(trees: List[Tree])(implicit src: SourceFile): Alternative = new Alternative(trees) def UnApply(fun: Tree, implicits: List[Tree], patterns: List[Tree])(implicit src: SourceFile): UnApply = new UnApply(fun, implicits, patterns) def ValDef(name: TermName, tpt: Tree, rhs: LazyTree)(implicit src: SourceFile): ValDef = new ValDef(name, tpt, rhs) - def DefDef(name: TermName, tparams: List[TypeDef], vparamss: List[List[ValDef]], tpt: Tree, rhs: LazyTree)(implicit src: SourceFile): DefDef = new DefDef(name, tparams, vparamss, tpt, rhs) + def DefDef(name: TermName, paramss: List[ParamClause], tpt: Tree, rhs: LazyTree)(implicit src: SourceFile): DefDef = new DefDef(name, paramss, tpt, rhs) def TypeDef(name: TypeName, rhs: Tree)(implicit src: SourceFile): TypeDef = new TypeDef(name, rhs) def Template(constr: DefDef, parents: List[Tree], derived: List[Tree], self: ValDef, body: LazyTreeList)(implicit src: SourceFile): Template = if (derived.isEmpty) new Template(constr, parents, self, body) @@ -481,7 +481,7 @@ object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo { def javaDotLangDot(name: Name)(implicit src: SourceFile): Select = Select(Select(Ident(nme.java), nme.lang), name) def makeConstructor(tparams: List[TypeDef], vparamss: List[List[ValDef]], rhs: Tree = EmptyTree)(using Context): DefDef = - DefDef(nme.CONSTRUCTOR, tparams, vparamss, TypeTree(), rhs) + DefDef(nme.CONSTRUCTOR, joinParams(tparams, vparamss), TypeTree(), rhs) def emptyConstructor(using Context): DefDef = makeConstructor(Nil, Nil) @@ -633,9 +633,9 @@ object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo { case tree: PatDef if (mods eq tree.mods) && (pats eq tree.pats) && (tpt eq tree.tpt) && (rhs eq tree.rhs) => tree case _ => finalize(tree, untpd.PatDef(mods, pats, tpt, rhs)(tree.source)) } - def ExtMethods(tree: Tree)(tparams: List[TypeDef], vparamss: List[List[ValDef]], methods: List[DefDef])(using Context): Tree = tree match - case tree: ExtMethods if (tparams eq tree.tparams) && (vparamss eq tree.vparamss) && (methods == tree.methods) => tree - case _ => finalize(tree, untpd.ExtMethods(tparams, vparamss, methods)(tree.source)) + def ExtMethods(tree: Tree)(paramss: List[ParamClause], methods: List[DefDef])(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 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)) @@ -700,8 +700,8 @@ object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo { cpy.ContextBounds(tree)(transformSub(bounds), transform(cxBounds)) case PatDef(mods, pats, tpt, rhs) => cpy.PatDef(tree)(mods, transform(pats), transform(tpt), transform(rhs)) - case ExtMethods(tparams, vparamss, methods) => - cpy.ExtMethods(tree)(transformSub(tparams), vparamss.mapConserve(transformSub(_)), transformSub(methods)) + case ExtMethods(paramss, methods) => + cpy.ExtMethods(tree)(transformParamss(paramss), transformSub(methods)) case ImportSelector(imported, renamed, bound) => cpy.ImportSelector(tree)(transformSub(imported), transform(renamed), transform(bound)) case Number(_, _) | TypedSplice(_) => @@ -759,8 +759,8 @@ object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo { this(this(x, bounds), cxBounds) case PatDef(mods, pats, tpt, rhs) => this(this(this(x, pats), tpt), rhs) - case ExtMethods(tparams, vparamss, methods) => - this(vparamss.foldLeft(this(x, tparams))(apply), methods) + case ExtMethods(paramss, methods) => + this(paramss.foldLeft(x)(apply), methods) case ImportSelector(imported, renamed, bound) => this(this(this(x, imported), renamed), bound) case Number(_, _) => diff --git a/compiler/src/dotty/tools/dotc/core/NamerOps.scala b/compiler/src/dotty/tools/dotc/core/NamerOps.scala index 5a52cb54da5f..8997d5ed1e1c 100644 --- a/compiler/src/dotty/tools/dotc/core/NamerOps.scala +++ b/compiler/src/dotty/tools/dotc/core/NamerOps.scala @@ -14,22 +14,28 @@ object NamerOps: /** The given type, unless `sym` is a constructor, in which case the * type of the constructed instance is returned */ - def effectiveResultType(sym: Symbol, typeParams: List[Symbol], givenTp: Type)(using Context): Type = - if (sym.name == nme.CONSTRUCTOR) sym.owner.typeRef.appliedTo(typeParams.map(_.typeRef)) + def effectiveResultType(sym: Symbol, paramss: List[List[Symbol]], givenTp: Type)(using Context): Type = + if sym.name == nme.CONSTRUCTOR then + paramss match + case TypeSymbols(tparams) :: _ => sym.owner.typeRef.appliedTo(tparams.map(_.typeRef)) + case _ => sym.owner.typeRef else givenTp - /** if isConstructor, make sure it has one non-implicit parameter list */ - def normalizeIfConstructor(termParamss: List[List[Symbol]], isConstructor: Boolean)(using Context): List[List[Symbol]] = - if (isConstructor && - (termParamss.isEmpty || termParamss.head.nonEmpty && termParamss.head.head.isOneOf(GivenOrImplicit))) - Nil :: termParamss - else - termParamss + /** if isConstructor, make sure it has one leading non-implicit parameter list */ + def normalizeIfConstructor(paramss: List[List[Symbol]], isConstructor: Boolean)(using Context): List[List[Symbol]] = + if !isConstructor then paramss + else paramss match + case Nil :: _ => paramss + case TermSymbols(vparam :: _) :: _ if !vparam.isOneOf(GivenOrImplicit) => paramss + case TypeSymbols(tparams) :: paramss1 => tparams :: normalizeIfConstructor(paramss1, isConstructor) + case _ => Nil :: paramss /** The method type corresponding to given parameters and result type */ - def methodType(typeParams: List[Symbol], valueParamss: List[List[Symbol]], resultType: Type, isJava: Boolean = false)(using Context): Type = - val monotpe = - valueParamss.foldRight(resultType) { (params, resultType) => + def methodType(paramss: List[List[Symbol]], resultType: Type, isJava: Boolean = false)(using Context): Type = + def recur(paramss: List[List[Symbol]]): Type = (paramss: @unchecked) match + case Nil => + resultType + case TermSymbols(params) :: paramss1 => val (isContextual, isImplicit, isErased) = if params.isEmpty then (false, false, false) else (params.head.is(Given), params.head.is(Implicit), params.head.is(Erased)) @@ -37,11 +43,12 @@ object NamerOps: if isJava then for param <- params do if param.info.isDirectRef(defn.ObjectClass) then param.info = defn.AnyType - make.fromSymbols(params, resultType) - } - if typeParams.nonEmpty then PolyType.fromParams(typeParams.asInstanceOf[List[TypeSymbol]], monotpe) - else if valueParamss.isEmpty then ExprType(monotpe) - else monotpe + make.fromSymbols(params, recur(paramss1)) + case TypeSymbols(tparams) :: paramss1 => + PolyType.fromParams(tparams, recur(paramss1)) + + if paramss.isEmpty then ExprType(resultType) else recur(paramss) + end methodType /** Add moduleClass or sourceModule functionality to completer * for a module or module class diff --git a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala index 1bd17d6c9778..ac08ea2eac6b 100644 --- a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala +++ b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala @@ -290,17 +290,15 @@ object SymDenotations { final def rawParamss_=(pss: List[List[Symbol]]): Unit = myParamss = pss - final def setParamss(tparams: List[Symbol], vparamss: List[List[Symbol]])(using Context): Unit = - rawParamss = (tparams :: vparamss).filterConserve(!_.isEmpty) - - final def setParamssFromDefs(tparams: List[TypeDef[?]], vparamss: List[List[ValDef[?]]])(using Context): Unit = - setParamss(tparams.map(_.symbol), vparamss.map(_.map(_.symbol))) + final def setParamss(paramss: List[List[Symbol]])(using Context): Unit = + rawParamss = paramss.filterConserve(!_.isEmpty) + final def setParamssFromDefs(paramss: List[tpd.ParamClause])(using Context): Unit = + setParamss(paramss.map(_.map(_.symbol))) /** The symbols of each type parameter list and value parameter list of this * method, or Nil if this isn't a method. * - * * Makes use of `rawParamss` when present, or constructs fresh parameter symbols otherwise. * This method can be allocation-heavy. */ diff --git a/compiler/src/dotty/tools/dotc/core/Symbols.scala b/compiler/src/dotty/tools/dotc/core/Symbols.scala index 016a8cabaf59..855f88690be8 100644 --- a/compiler/src/dotty/tools/dotc/core/Symbols.scala +++ b/compiler/src/dotty/tools/dotc/core/Symbols.scala @@ -861,6 +861,22 @@ object Symbols { copies } + /** Matches lists of term symbols, including the empty list. + * All symbols in the list are assumed to be of the same kind. + */ + object TermSymbols: + def unapply(xs: List[Symbol])(using Context): Option[List[TermSymbol]] = xs match + case (x: Symbol) :: _ if x.isType => None + case _ => Some(xs.asInstanceOf[List[TermSymbol]]) + + /** Matches lists of type symbols, excluding the empty list. + * All symbols in the list are assumed to be of the same kind. + */ + object TypeSymbols: + def unapply(xs: List[Symbol])(using Context): Option[List[TypeSymbol]] = xs match + case (x: Symbol) :: _ if x.isType => Some(xs.asInstanceOf[List[TypeSymbol]]) + case _ => None + // ----- Locating predefined symbols ---------------------------------------- def requiredPackage(path: PreName)(using Context): TermSymbol = { diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala b/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala index 08fde74149b4..10af44c76169 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala @@ -550,16 +550,20 @@ class TreePickler(pickler: TastyPickler) { case tree: ValDef => pickleDef(VALDEF, tree, tree.tpt, tree.rhs) case tree: DefDef => - def pickleParamss(paramss: List[List[ValDef]]): Unit = paramss match + def pickleParamss(paramss: List[ParamClause]): Unit = paramss match case Nil => - case params :: rest => + case Nil :: rest => + writeByte(EMPTYCLAUSE) + pickleParamss(rest) + case (params @ (param1 :: _)) :: rest => pickleParams(params) - if params.isEmpty || rest.nonEmpty then writeByte(PARAMEND) + rest match + case (param2 :: _) :: _ + if param1.isInstanceOf[untpd.TypeDef] == param2.isInstanceOf[untpd.TypeDef] => + writeByte(SPLITCLAUSE) + case _ => pickleParamss(rest) - def pickleAllParams = - pickleParams(tree.tparams) - pickleParamss(tree.vparamss) - pickleDef(DEFDEF, tree, tree.tpt, tree.rhs, pickleAllParams) + pickleDef(DEFDEF, tree, tree.tpt, tree.rhs, pickleParamss(tree.paramss)) case tree: TypeDef => pickleDef(TYPEDEF, tree, tree.rhs) case tree: Template => diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala b/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala index 2bbdc68f9cc2..1c58ec570f24 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala @@ -139,7 +139,7 @@ class TreeUnpickler(reader: TastyReader, def skipParams(): Unit = while val tag = nextByte - tag == PARAM || tag == TYPEPARAM || tag == PARAMEND + tag == PARAM || tag == TYPEPARAM || tag == EMPTYCLAUSE || tag == SPLITCLAUSE do skipTree() /** Record all directly nested definitions and templates in current tree @@ -780,12 +780,15 @@ class TreeUnpickler(reader: TastyReader, val tag = readByte() val end = readEnd() - def readParamss(using Context): List[List[ValDef]] = nextByte match - case PARAM | PARAMEND => - readParams[ValDef](PARAM) :: - (if nextByte == PARAMEND then { readByte(); readParamss } else Nil) - case _ => - Nil + def readParamss()(using Context): List[ParamClause] = + def readRest() = + if nextByte == SPLITCLAUSE then readByte() + readParamss() + nextByte match + case PARAM => readParams[ValDef](PARAM) :: readRest() + case TYPEPARAM => readParams[TypeDef](TYPEPARAM) :: readRest() + case EMPTYCLAUSE => readByte(); Nil :: readRest() + case _ => Nil val localCtx = localContext(sym) @@ -803,10 +806,10 @@ class TreeUnpickler(reader: TastyReader, def ValDef(tpt: Tree) = ta.assignType(untpd.ValDef(sym.name.asTermName, tpt, readRhs(using localCtx)), sym) - def DefDef(tparams: List[TypeDef], vparamss: List[List[ValDef]], tpt: Tree) = - sym.setParamssFromDefs(tparams, vparamss) + def DefDef(paramss: List[ParamClause], tpt: Tree) = + sym.setParamssFromDefs(paramss) ta.assignType( - untpd.DefDef(sym.name.asTermName, tparams, vparamss, tpt, readRhs(using localCtx)), + untpd.DefDef(sym.name.asTermName, paramss, tpt, readRhs(using localCtx)), sym) def TypeDef(rhs: Tree) = @@ -818,15 +821,13 @@ class TreeUnpickler(reader: TastyReader, pickling.println(s"reading def of $name at $start") val tree: MemberDef = tag match { case DEFDEF => - val tparams = readParams[TypeDef](TYPEPARAM)(using localCtx) - val vparamss = readParamss(using localCtx) + val paramDefss = readParamss()(using localCtx) val tpt = readTpt()(using localCtx) - val typeParams = tparams.map(_.symbol) - val valueParamss = normalizeIfConstructor( - vparamss.nestedMap(_.symbol), name == nme.CONSTRUCTOR) - val resType = effectiveResultType(sym, typeParams, tpt.tpe) - sym.info = methodType(typeParams, valueParamss, resType) - DefDef(tparams, vparamss, tpt) + val paramss = normalizeIfConstructor( + paramDefss.nestedMap(_.symbol), name == nme.CONSTRUCTOR) + val resType = effectiveResultType(sym, paramss, tpt.tpe) + sym.info = methodType(paramss, resType) + DefDef(paramDefss, tpt) case VALDEF => val tpt = readTpt()(using localCtx) sym.info = tpt.tpe @@ -872,7 +873,7 @@ class TreeUnpickler(reader: TastyReader, else { sym.info = ExprType(tpt.tpe) pickling.println(i"reading param alias $name -> $currentAddr") - DefDef(Nil, Nil, tpt) + DefDef(Nil, tpt) } } goto(end) diff --git a/compiler/src/dotty/tools/dotc/interactive/Interactive.scala b/compiler/src/dotty/tools/dotc/interactive/Interactive.scala index a54b24fe62cc..aa2359f33eb2 100644 --- a/compiler/src/dotty/tools/dotc/interactive/Interactive.scala +++ b/compiler/src/dotty/tools/dotc/interactive/Interactive.scala @@ -111,7 +111,7 @@ object Interactive { val classTree = funSym.topLevelClass.asClass.rootTree val paramSymbol = for { - DefDef(_, _, paramss, _, _) <- tpd.defPath(funSym, classTree).lastOption + DefDef(_, paramss, _, _) <- tpd.defPath(funSym, classTree).lastOption param <- paramss.flatten.find(_.name == name) } yield param.symbol @@ -288,8 +288,7 @@ object Interactive { case tree: DefDef => assert(tree.symbol.exists) val localCtx = outer.localContext(tree, tree.symbol).setNewScope - for (tparam <- tree.tparams) localCtx.enter(tparam.symbol) - for (vparams <- tree.vparamss; vparam <- vparams) localCtx.enter(vparam.symbol) + for params <- tree.paramss; param <- params do localCtx.enter(param.symbol) // Note: this overapproximates visibility a bit, since value parameters are only visible // in subsequent parameter sections localCtx diff --git a/compiler/src/dotty/tools/dotc/parsing/JavaParsers.scala b/compiler/src/dotty/tools/dotc/parsing/JavaParsers.scala index 549ca054c136..e54ea0b2b6aa 100644 --- a/compiler/src/dotty/tools/dotc/parsing/JavaParsers.scala +++ b/compiler/src/dotty/tools/dotc/parsing/JavaParsers.scala @@ -134,7 +134,7 @@ object JavaParsers { def makeConstructor(formals: List[Tree], tparams: List[TypeDef], flags: FlagSet = Flags.JavaDefined): DefDef = { val vparams = formals.zipWithIndex.map { case (p, i) => makeSyntheticParam(i + 1, p) } - DefDef(nme.CONSTRUCTOR, tparams, List(vparams), TypeTree(), EmptyTree).withMods(Modifiers(flags)) + DefDef(nme.CONSTRUCTOR, joinParams(tparams, List(vparams)), TypeTree(), EmptyTree).withMods(Modifiers(flags)) } // ------------- general parsing --------------------------- @@ -509,8 +509,8 @@ object JavaParsers { optThrows() List { atSpan(start) { - DefDef(nme.CONSTRUCTOR, tparams, - List(vparams), TypeTree(), methodBody()).withMods(mods) + DefDef(nme.CONSTRUCTOR, joinParams(tparams, List(vparams)), + TypeTree(), methodBody()).withMods(mods) } } } @@ -547,7 +547,7 @@ object JavaParsers { //if (inInterface) mods1 |= Flags.Deferred List { atSpan(start, nameOffset) { - DefDef(name.toTermName, tparams, List(vparams), rtpt, body).withMods(mods1 | Flags.Method) + DefDef(name.toTermName, joinParams(tparams, List(vparams)), rtpt, body).withMods(mods1 | Flags.Method) } } } @@ -844,7 +844,7 @@ object JavaParsers { makeParam(dd.name, dd.tpt) } val constr = DefDef(nme.CONSTRUCTOR, - List(), List(constructorParams), TypeTree(), EmptyTree).withMods(Modifiers(Flags.JavaDefined)) + List(constructorParams), TypeTree(), EmptyTree).withMods(Modifiers(Flags.JavaDefined)) val templ = makeTemplate(annotationParents, constr :: body, List(), true) val annot = atSpan(start, nameOffset) { TypeDef(name, templ).withMods(mods | Flags.Abstract) @@ -879,12 +879,12 @@ object JavaParsers { (List(), List()) val predefs = List( DefDef( - nme.values, List(), + nme.values, ListOfNil, arrayOf(enumType), unimplementedExpr).withMods(Modifiers(Flags.JavaDefined | Flags.JavaStatic | Flags.Method)), DefDef( - nme.valueOf, List(), + nme.valueOf, List(List(makeParam("x".toTermName, TypeTree(StringType)))), enumType, unimplementedExpr).withMods(Modifiers(Flags.JavaDefined | Flags.JavaStatic | Flags.Method))) diff --git a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala index 9849400da403..17053130c34a 100644 --- a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala +++ b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala @@ -1298,7 +1298,7 @@ object Parsers { case stat: MemberDef if !stat.name.isEmpty => if stat.name == nme.CONSTRUCTOR then in.token == THIS else in.isIdent && in.name == stat.name.toTermName - case ExtMethods(_, _, _) => + case ExtMethods(_, _) => in.token == IDENTIFIER && in.name == nme.extension case PackageDef(pid: RefTree, _) => in.isIdent && in.name == pid.name @@ -2997,7 +2997,7 @@ object Parsers { if in.token == RPAREN && !prefix && !impliedMods.is(Given) then Nil else val clause = - if prefix then param() :: Nil + if prefix && !isIdent(nme.using) then param() :: Nil else paramMods() if givenOnly && !impliedMods.is(Given) then @@ -3306,7 +3306,7 @@ object Parsers { accept(EQUALS) expr() - val ddef = DefDef(name, tparams, vparamss, tpt, rhs) + val ddef = DefDef(name, joinParams(tparams, vparamss), tpt, rhs) if (isBackquoted(ident)) ddef.pushAttachment(Backquoted, ()) finalizeDef(ddef, mods1, start) } @@ -3389,7 +3389,6 @@ object Parsers { * | [‘case’] ‘object’ ObjectDef * | ‘enum’ EnumDef * | ‘given’ GivenDef - * | ‘extension’ ExtensionDef */ def tmplDef(start: Int, mods: Modifiers): Tree = in.token match { @@ -3507,9 +3506,9 @@ object Parsers { syntaxError(i"no extension method allowed here since leading parameter was already given", stat.span) else if !stat.mods.is(ExtensionMethod) && vparamss.isEmpty then syntaxError(i"an extension method is required here", stat.span) - else if tparams.nonEmpty && stat.tparams.nonEmpty then + else if tparams.nonEmpty && stat.leadingTypeParams.nonEmpty then syntaxError(i"extension method cannot have type parameters since some were already given previously", - stat.tparams.head.span) + stat.leadingTypeParams.head.span) else if stat.rhs.isEmpty then syntaxError(i"extension method cannot be abstract", stat.span) case EmptyTree => @@ -3544,11 +3543,11 @@ object Parsers { mods1 |= Lazy ValDef(name, parents.head, subExpr()) else - DefDef(name, tparams, vparamss, parents.head, subExpr()) + DefDef(name, joinParams(tparams, vparamss), parents.head, subExpr()) else if in.token != WITH && parentsIsType then if name.isEmpty then syntaxError(em"anonymous given cannot be abstract") - DefDef(name, tparams, vparamss, parents.head, EmptyTree) + DefDef(name, joinParams(tparams, vparamss), parents.head, EmptyTree) else val tparams1 = tparams.map(tparam => tparam.withMods(tparam.mods | PrivateLocal)) val vparamss1 = vparamss.map(_.map(vparam => @@ -3566,8 +3565,15 @@ object Parsers { def extension(): ExtMethods = val start = in.skipToken() val tparams = typeParamClauseOpt(ParamOwner.Def) - val extParams = paramClause(0, prefix = true) - val givenParamss = paramClauses(givenOnly = true) + val leadParamss = ListBuffer[List[ValDef]]() + var nparams = 0 + while + val extParams = paramClause(nparams, prefix = true) + leadParamss += extParams + nparams += extParams.length + isUsingClause(extParams) + do () + leadParamss ++= paramClauses(givenOnly = true) if in.token == COLON then syntaxError("no `:` expected here") in.nextToken() @@ -3579,7 +3585,7 @@ object Parsers { newLineOptWhenFollowedBy(LBRACE) if in.isNestedStart then inDefScopeBraces(extMethods()) else { syntaxError("Extension without extension methods"); Nil } - val result = atSpan(start)(ExtMethods(tparams, extParams :: givenParamss, methods)) + val result = atSpan(start)(ExtMethods(joinParams(tparams, leadParamss.toList), methods)) val comment = in.getDocComment(start) if comment.isDefined then for meth <- methods do @@ -3835,7 +3841,7 @@ object Parsers { val problem = tree match case tree: MemberDef if !(tree.mods.flags & ModifierFlags).isEmpty => i"refinement cannot be ${(tree.mods.flags & ModifierFlags).flagStrings().mkString("`", "`, `", "`")}" - case tree: DefDef if tree.vparamss.nestedExists(!_.rhs.isEmpty) => + case tree: DefDef if tree.termParamss.nestedExists(!_.rhs.isEmpty) => i"refinement cannot have default arguments" case tree: ValOrDefDef => if tree.rhs.isEmpty then "" diff --git a/compiler/src/dotty/tools/dotc/printing/DecompilerPrinter.scala b/compiler/src/dotty/tools/dotc/printing/DecompilerPrinter.scala index a72ffa474e43..bd1cc574cf27 100644 --- a/compiler/src/dotty/tools/dotc/printing/DecompilerPrinter.scala +++ b/compiler/src/dotty/tools/dotc/printing/DecompilerPrinter.scala @@ -18,13 +18,13 @@ class DecompilerPrinter(_ctx: Context) extends RefinedPrinter(_ctx) { override protected def blockToText[T >: Untyped](block: Block[T]): Text = block match { - case Block(DefDef(_, _, _, _, Trees.If(cond, Trees.Block(body :: Nil, _), _)) :: Nil, y) if y.symbol.name == nme.WHILE_PREFIX => + case Block(DefDef(_, _, _, Trees.If(cond, Trees.Block(body :: Nil, _), _)) :: Nil, y) if y.symbol.name == nme.WHILE_PREFIX => keywordText("while") ~ " (" ~ toText(cond) ~ ")" ~ toText(body) - case Block(DefDef(_, _, _, _, Trees.Block(body :: Nil, Trees.If(cond, _, _))) :: Nil, y) if y.symbol.name == nme.DO_WHILE_PREFIX => + case Block(DefDef(_, _, _, Trees.Block(body :: Nil, Trees.If(cond, _, _))) :: Nil, y) if y.symbol.name == nme.DO_WHILE_PREFIX => keywordText("do") ~ toText(body) ~ keywordText("while") ~ " (" ~ toText(cond) ~ ")" - case Block((meth @ DefDef(nme.ANON_FUN, _, _, _, _)) :: Nil, _: Closure[T]) => + case Block((meth @ DefDef(nme.ANON_FUN, _, _, _)) :: Nil, _: Closure[T]) => withEnclosingDef(meth) { - addVparamssText("", meth.vparamss) ~ " => " ~ toText(meth.rhs) + addParamssText("", meth.termParamss) ~ " => " ~ toText(meth.rhs) } case _ => super.blockToText(block) diff --git a/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala b/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala index dabc9d25acf1..5cf45fd2078d 100644 --- a/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala +++ b/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala @@ -492,7 +492,7 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) { toTextLocal(tpt) ~ "[" ~ Text(args.map(argText), ", ") ~ "]" case LambdaTypeTree(tparams, body) => changePrec(GlobalPrec) { - tparamsText(tparams) ~ " =>> " ~ toText(body) + paramsText(tparams) ~ " =>> " ~ toText(body) } case TermLambdaTypeTree(params, body) => changePrec(GlobalPrec) { @@ -523,7 +523,7 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) { ("(" ~ toTextGlobal(implicits, ", ") ~ ")" provided implicits.nonEmpty) case tree @ ValDef(_, _, _) => valDefToText(tree) - case tree @ DefDef(_, _, _, _, _) => + case tree @ DefDef(_, _, _, _) => defDefToText(tree) case tree @ TypeDef(name, rhs) => def typeDefText(tparamsText: => Text, rhsText: => Text) = @@ -538,7 +538,7 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) { case rhs: TypeBoundsTree => typeDefText(tparamsTxt, toText(rhs)) case LambdaTypeTree(tparams, body) if printMemberArgs => - recur(body, tparamsText(tparams), false) + recur(body, paramsText(tparams), false) case rhs: TypeTree if isBounds(rhs.typeOpt) => typeDefText(tparamsTxt, toText(rhs)) case rhs => @@ -549,9 +549,8 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) { keywordText("import ") ~ importText(expr, selectors) case Export(expr, selectors) => keywordText("export ") ~ importText(expr, selectors) - case ExtMethods(tparams, vparamss, mdefs) => - keywordText("extension ") - ~ addVparamssText(tparamsText(tparams), vparamss) + case ExtMethods(paramss, mdefs) => + addParamssText(keywordText("extension "), paramss) ~ " " ~ (if mdefs.length == 1 then toText(mdefs.head) else blockText(mdefs)) case packageDef: PackageDef => packageDefText(packageDef) @@ -646,8 +645,8 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) { keywordStr("${") ~ toTextGlobal(dropBlock(tree)) ~ keywordStr("}") case TypSplice(tree) => keywordStr("${") ~ toTextGlobal(dropBlock(tree)) ~ keywordStr("}") - case tree: Applications.IntegratedTypeArgs => - toText(tree.app) ~ Str("(with integrated type args)").provided(printDebug) + case tree: Applications.ExtMethodApply => + toText(tree.app) ~ Str("(ext method apply)").provided(printDebug) case Thicket(trees) => "Thicket {" ~~ toTextGlobal(trees, "\n") ~~ "}" case MacroTree(call) => @@ -772,11 +771,18 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) { else treeText } - def tparamsText[T >: Untyped](params: List[Tree[T]]): Text = - "[" ~ toText(params, ", ") ~ "]" provided params.nonEmpty + def paramsText[T>: Untyped](params: ParamClause[T]): Text = (params: @unchecked) match + case Nil => + "()" + case untpd.ValDefs(vparams @ (vparam :: _)) => + "(" ~ keywordText("using ").provided(vparam.mods.is(Given)) + ~ keywordText("erased ").provided(vparam.mods.is(Erased)) + ~ toText(vparams, ", ") ~ ")" + case untpd.TypeDefs(tparams) => + "[" ~ toText(tparams, ", ") ~ "]" - def addVparamssText[T >: Untyped](leading: Text, vparamss: List[List[ValDef[T]]]): Text = - vparamss.foldLeft(leading)((txt, params) => txt ~ paramsText(params)) + def addParamssText[T >: Untyped](leading: Text, paramss: List[ParamClause[T]]): Text = + paramss.foldLeft(leading)((txt, params) => txt ~ paramsText(params)) protected def valDefToText[T >: Untyped](tree: ValDef[T]): Text = { import untpd._ @@ -787,47 +793,60 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) { } } - private def paramsText[T>: Untyped](params: List[ValDef[T]]) = - "(" ~ keywordText("using ").provided(params.nonEmpty && params.head.mods.is(Given)) - ~ keywordText("erased ").provided(params.nonEmpty && params.head.mods.is(Erased)) - ~ toText(params, ", ") ~ ")" - protected def defDefToText[T >: Untyped](tree: DefDef[T]): Text = { import untpd._ dclTextOr(tree) { val defKeyword = modText(tree.mods, tree.symbol, keywordStr("def"), isType = false) val isExtension = tree.hasType && tree.symbol.is(ExtensionMethod) withEnclosingDef(tree) { - val (prefix, vparamss) = + val coreSig = if isExtension then - val (leadingParams, otherParamss) = (tree.vparamss: @unchecked) match - case vparams1 :: vparams2 :: rest if tree.name.isRightAssocOperatorName => - (vparams2, vparams1 :: rest) - case vparams1 :: rest => - (vparams1, rest) - (keywordStr("extension") ~~ paramsText(leadingParams) - ~~ (defKeyword ~~ valDefText(nameIdText(tree))).close, - otherParamss) - else (defKeyword ~~ valDefText(nameIdText(tree)), tree.vparamss) - - addVparamssText(prefix ~ tparamsText(tree.tparams), vparamss) ~ - optAscription(tree.tpt) ~ - optText(tree.rhs)(" = " ~ keywordText("macro ").provided(tree.symbol.isScala2Macro) ~ _) + val paramss = + if tree.name.isRightAssocOperatorName then + // we have the encoding: leadingUsingOrTypeParams rightParam trailingUsing leftParam + // we need to swap rightParam and leftParam + val (leadingUsing, rest1) = tree.paramss.span(isUsingOrTypeParamClause) + val (rightParamss, rest2) = rest1.splitAt(1) + val (trailingUsing, rest3) = rest2.span(isUsingClause) + val (leftParamss, rest4) = rest3.splitAt(1) + if leftParamss.nonEmpty then + leadingUsing ::: leftParamss ::: trailingUsing ::: rightParamss ::: rest4 + else + tree.paramss // it wasn't a binary operator, after all. + else + tree.paramss + val trailingParamss = paramss + .dropWhile(isUsingOrTypeParamClause) + .drop(1) + .dropWhile(isUsingClause) + val leadingParamss = paramss.take(paramss.length - trailingParamss.length) + addParamssText( + addParamssText(keywordStr("extension "), leadingParamss) + ~~ (defKeyword ~~ valDefText(nameIdText(tree))).close, + trailingParamss) + else + addParamssText(defKeyword ~~ valDefText(nameIdText(tree)), tree.paramss) + + coreSig + ~ optAscription(tree.tpt) + ~ optText(tree.rhs)(" = " ~ keywordText("macro ").provided(tree.symbol.isScala2Macro) ~ _) } } } protected def toTextTemplate(impl: Template, ofNew: Boolean = false): Text = { - val Template(constr @ DefDef(_, tparams, vparamss, _, _), _, self, _) = impl - val tparamsTxt = withEnclosingDef(constr) { tparamsText(tparams) } + val Template(constr @ DefDef(_, paramss, _, _), _, self, _) = impl + val tparamsTxt = withEnclosingDef(constr) { + paramsText(constr.leadingTypeParams) provided constr.leadingTypeParams.nonEmpty + } val primaryConstrs = if (constr.rhs.isEmpty) Nil else constr :: Nil val prefix: Text = - if (vparamss.isEmpty || primaryConstrs.nonEmpty) tparamsTxt + if (constr.trailingParamss.isEmpty || primaryConstrs.nonEmpty) tparamsTxt else { var modsText = modText(constr.mods, constr.symbol, "", isType = false) if (!modsText.isEmpty) modsText = " " ~ modsText if (constr.mods.hasAnnotations && !constr.mods.hasFlags) modsText = modsText ~~ " this" - withEnclosingDef(constr) { addVparamssText(tparamsTxt ~~ modsText, vparamss) } + withEnclosingDef(constr) { addParamssText(tparamsTxt ~~ modsText, constr.trailingParamss) } } val parentsText = Text(impl.parents.map(constrText), if (ofNew) keywordStr(" with ") else ", ") val derivedText = Text(impl.derived.map(toText(_)), ", ") diff --git a/compiler/src/dotty/tools/dotc/reporting/messages.scala b/compiler/src/dotty/tools/dotc/reporting/messages.scala index ec522e12efa5..2c3689749334 100644 --- a/compiler/src/dotty/tools/dotc/reporting/messages.scala +++ b/compiler/src/dotty/tools/dotc/reporting/messages.scala @@ -403,8 +403,8 @@ import transform.SymUtils._ def explain = { val TypeDef(name, impl @ Template(constr0, parents, self, _)) = cdef val exampleArgs = - if(constr0.vparamss.isEmpty) "..." - else constr0.vparamss(0).map(_.withMods(untpd.Modifiers()).show).mkString(", ") + if(constr0.termParamss.isEmpty) "..." + else constr0.termParamss(0).map(_.withMods(untpd.Modifiers()).show).mkString(", ") def defHasBody[T] = impl.body.exists(!_.isEmpty) val exampleBody = if (defHasBody) "{\n ...\n }" else "" em"""|There may not be any method, member or object in scope with the same name as @@ -2432,7 +2432,7 @@ import transform.SymUtils._ def explain = em"""|Extension method: | `${mdef}` - |has type parameters `[${mdef.tparams.map(_.show).mkString(",")}]`, while the extension clause has + |has type parameters `[${mdef.leadingTypeParams.map(_.show).mkString(",")}]`, while the extension clause has |it's own type parameters. Please consider moving these to the extension clause's type parameter list. |""".stripMargin } diff --git a/compiler/src/dotty/tools/dotc/semanticdb/ExtractSemanticDB.scala b/compiler/src/dotty/tools/dotc/semanticdb/ExtractSemanticDB.scala index 4ee3b4db9210..e1b5abe799e1 100644 --- a/compiler/src/dotty/tools/dotc/semanticdb/ExtractSemanticDB.scala +++ b/compiler/src/dotty/tools/dotc/semanticdb/ExtractSemanticDB.scala @@ -162,14 +162,13 @@ class ExtractSemanticDB extends Phase: traverse(tree.tpt) case tree: DefDef if tree.symbol.isConstructor => // ignore typeparams for secondary ctors - tree.vparamss.foreach(_.foreach(traverse)) + tree.trailingParamss.foreach(_.foreach(traverse)) traverse(tree.rhs) case tree: (DefDef | ValDef) if tree.symbol.isSyntheticWithIdent => tree match case tree: DefDef => - tree.tparams.foreach(tparam => registerSymbolSimple(tparam.symbol)) - tree.vparamss.foreach(_.foreach(vparam => registerSymbolSimple(vparam.symbol))) + tree.paramss.foreach(_.foreach(param => registerSymbolSimple(param.symbol))) case _ => if !tree.symbol.isGlobal then localBodies(tree.symbol) = tree.rhs @@ -185,7 +184,7 @@ class ExtractSemanticDB extends Phase: if !excludeDef(ctorSym) then traverseAnnotsOfDefinition(ctorSym) registerDefinition(ctorSym, tree.constr.nameSpan.startPos, Set.empty, tree.source) - ctorParams(tree.constr.vparamss, tree.body) + ctorParams(tree.constr.termParamss, tree.body) for parent <- tree.parentsOrDerived if parent.span.hasLength do traverse(parent) val selfSpan = tree.self.span @@ -498,7 +497,7 @@ class ExtractSemanticDB extends Phase: extension (tree: DefDef) private def isSetterDef(using Context): Boolean = - tree.name.isSetterName && tree.mods.is(Accessor) && tree.vparamss.isSingleArg + tree.name.isSetterName && tree.mods.is(Accessor) && tree.termParamss.isSingleArg private def findGetters(ctorParams: Set[Names.TermName], body: List[Tree])(using Context): Map[Names.TermName, ValDef] = if ctorParams.isEmpty || body.isEmpty then diff --git a/compiler/src/dotty/tools/dotc/transform/AccessProxies.scala b/compiler/src/dotty/tools/dotc/transform/AccessProxies.scala index 321aadac4130..6d6dc6fb3956 100644 --- a/compiler/src/dotty/tools/dotc/transform/AccessProxies.scala +++ b/compiler/src/dotty/tools/dotc/transform/AccessProxies.scala @@ -37,23 +37,24 @@ abstract class AccessProxies { */ private def accessorDefs(cls: Symbol)(using Context): Iterator[DefDef] = for (accessor <- cls.info.decls.iterator; accessed <- accessedBy.remove(accessor).toOption) yield - polyDefDef(accessor.asTerm, tps => argss => { + DefDef(accessor.asTerm, prefss => { def numTypeParams = accessed.info match { case info: PolyType => info.paramNames.length case _ => 0 } - val (accessRef, forwardedTypes, forwardedArgss) = + val (targs, argss) = splitArgs(prefss) + val (accessRef, forwardedTpts, forwardedArgss) = if (passReceiverAsArg(accessor.name)) - (argss.head.head.select(accessed), tps.takeRight(numTypeParams), argss.tail) + (argss.head.head.select(accessed), targs.takeRight(numTypeParams), argss.tail) else (if (accessed.isStatic) ref(accessed) else ref(TermRef(cls.thisType, accessed)), - tps, argss) + targs, argss) val rhs = if (accessor.name.isSetterName && forwardedArgss.nonEmpty && forwardedArgss.head.nonEmpty) // defensive conditions accessRef.becomes(forwardedArgss.head.head) else - accessRef.appliedToTypes(forwardedTypes).appliedToArgss(forwardedArgss) + accessRef.appliedToTypeTrees(forwardedTpts).appliedToArgss(forwardedArgss) rhs.withSpan(accessed.span) }) diff --git a/compiler/src/dotty/tools/dotc/transform/BetaReduce.scala b/compiler/src/dotty/tools/dotc/transform/BetaReduce.scala index 4d8e64eecaab..17ce6020e2a9 100644 --- a/compiler/src/dotty/tools/dotc/transform/BetaReduce.scala +++ b/compiler/src/dotty/tools/dotc/transform/BetaReduce.scala @@ -69,7 +69,7 @@ object BetaReduce: /** Beta-reduces a call to `ddef` with arguments `argSyms` */ def apply(ddef: DefDef, args: List[Tree])(using Context) = val bindings = List.newBuilder[ValDef] - val vparams = ddef.vparamss.iterator.flatten.toList + val vparams = ddef.termParamss.iterator.flatten.toList assert(args.hasSameLengthAs(vparams)) val argSyms = for (arg, param) <- args.zip(vparams) yield diff --git a/compiler/src/dotty/tools/dotc/transform/CompleteJavaEnums.scala b/compiler/src/dotty/tools/dotc/transform/CompleteJavaEnums.scala index 9a7665d2286e..4aa352f60f1b 100644 --- a/compiler/src/dotty/tools/dotc/transform/CompleteJavaEnums.scala +++ b/compiler/src/dotty/tools/dotc/transform/CompleteJavaEnums.scala @@ -89,8 +89,10 @@ class CompleteJavaEnums extends MiniPhase with InfoTransformer { thisPhase => val sym = tree.symbol if sym.isConstructor && sym.owner.derivesFromJavaEnum then val tree1 = cpy.DefDef(tree)( - vparamss = tree.vparamss.init :+ (tree.vparamss.last ++ addedParams(sym, isLocal=false, Param))) - sym.setParamssFromDefs(tree1.tparams, tree1.vparamss) + paramss = tree.paramss.init + :+ (tree.paramss.last.asInstanceOf[List[ValDef]] + ++ addedParams(sym, isLocal=false, Param))) + sym.setParamssFromDefs(tree1.paramss) tree1 else tree } diff --git a/compiler/src/dotty/tools/dotc/transform/Constructors.scala b/compiler/src/dotty/tools/dotc/transform/Constructors.scala index a778ed2325b5..16666795ab77 100644 --- a/compiler/src/dotty/tools/dotc/transform/Constructors.scala +++ b/compiler/src/dotty/tools/dotc/transform/Constructors.scala @@ -127,7 +127,7 @@ class Constructors extends MiniPhase with IdentityDenotTransformer { thisPhase = override def transformTemplate(tree: Template)(using Context): Tree = { val cls = ctx.owner.asClass - val constr @ DefDef(nme.CONSTRUCTOR, Nil, vparams :: Nil, _, EmptyTree) = tree.constr + val constr @ DefDef(nme.CONSTRUCTOR, (vparams: List[ValDef] @unchecked) :: Nil, _, EmptyTree) = tree.constr // Produce aligned accessors and constructor parameters. We have to adjust // for any outer parameters, which are last in the sequence of original @@ -207,7 +207,7 @@ class Constructors extends MiniPhase with IdentityDenotTransformer { thisPhase = constrStats += intoConstr(stat, sym) } else dropped += sym - case stat @ DefDef(name, _, _, tpt, _) + case stat @ DefDef(name, _, tpt, _) if stat.symbol.isGetter && stat.symbol.owner.is(Trait) && !stat.symbol.is(Lazy) && !stat.symbol.isConstExprFinalVal => val sym = stat.symbol assert(isRetained(sym), sym) @@ -232,7 +232,7 @@ class Constructors extends MiniPhase with IdentityDenotTransformer { thisPhase = else sym.accessorNamed(Mixin.traitSetterName(sym.asTerm)) constrStats += Apply(ref(setter), intoConstr(stat.rhs, sym).withSpan(stat.span) :: Nil) clsStats += cpy.DefDef(stat)(rhs = EmptyTree) - case DefDef(nme.CONSTRUCTOR, _, ((outerParam @ ValDef(nme.OUTER, _, _)) :: _) :: Nil, _, _) => + case DefDef(nme.CONSTRUCTOR, ((outerParam @ ValDef(nme.OUTER, _, _)) :: _) :: Nil, _, _) => clsStats += mapOuter(outerParam.symbol).transform(stat) case _: DefTree => clsStats += stat diff --git a/compiler/src/dotty/tools/dotc/transform/ElimRepeated.scala b/compiler/src/dotty/tools/dotc/transform/ElimRepeated.scala index c02a434da7ef..c1be520cf0d5 100644 --- a/compiler/src/dotty/tools/dotc/transform/ElimRepeated.scala +++ b/compiler/src/dotty/tools/dotc/transform/ElimRepeated.scala @@ -222,15 +222,14 @@ class ElimRepeated extends MiniPhase with InfoTransformer { thisPhase => .get .symbol.asTerm // Generate the method - val forwarderDef = polyDefDef(forwarderSym, trefs => vrefss => { - val init :+ (last :+ vararg) = vrefss + val forwarderDef = DefDef(forwarderSym, prefss => { + val init :+ (last :+ vararg) = prefss // Can't call `.argTypes` here because the underlying array type is of the // form `Array[? <: SomeType]`, so we need `.argInfos` to get the `TypeBounds`. val elemtp = vararg.tpe.widen.argInfos.head ref(sym.termRef) - .appliedToTypes(trefs) .appliedToArgss(init) - .appliedToArgs(last :+ wrapArray(vararg, elemtp)) + .appliedToTermArgs(last :+ wrapArray(vararg, elemtp)) }) Thicket(tree, forwarderDef) else diff --git a/compiler/src/dotty/tools/dotc/transform/Erasure.scala b/compiler/src/dotty/tools/dotc/transform/Erasure.scala index 28417bcf5930..0d80ef87056f 100644 --- a/compiler/src/dotty/tools/dotc/transform/Erasure.scala +++ b/compiler/src/dotty/tools/dotc/transform/Erasure.scala @@ -893,13 +893,15 @@ object Erasure { else val restpe = if sym.isConstructor then defn.UnitType else sym.info.resultType var vparams = outerParamDefs(sym) - ::: ddef.vparamss.flatten.filterConserve(!_.symbol.is(Flags.Erased)) + ::: ddef.paramss.collect { + case untpd.ValDefs(vparams) => vparams + }.flatten.filterConserve(!_.symbol.is(Flags.Erased)) def skipContextClosures(rhs: Tree, crCount: Int)(using Context): Tree = if crCount == 0 then rhs else rhs match case closureDef(meth) => - val contextParams = meth.vparamss.head + val contextParams = meth.termParamss.head for param <- contextParams do param.symbol.copySymDenotation(owner = sym).installAfter(erasurePhase) vparams ++= contextParams @@ -921,8 +923,7 @@ object Erasure { rhs1 = Block(paramDefs, rhs1) val ddef1 = untpd.cpy.DefDef(ddef)( - tparams = Nil, - vparamss = vparams :: Nil, + paramss = vparams :: Nil, tpt = untpd.TypedSplice(TypeTree(restpe).withSpan(ddef.tpt.span)), rhs = rhs1) super.typedDefDef(ddef1, sym) diff --git a/compiler/src/dotty/tools/dotc/transform/ExpandSAMs.scala b/compiler/src/dotty/tools/dotc/transform/ExpandSAMs.scala index 137ce38e9b12..c0ea4adee353 100644 --- a/compiler/src/dotty/tools/dotc/transform/ExpandSAMs.scala +++ b/compiler/src/dotty/tools/dotc/transform/ExpandSAMs.scala @@ -111,7 +111,7 @@ class ExpandSAMs extends MiniPhase: } } - val closureDef(anon @ DefDef(_, _, List(List(param)), _, _)) = tree + val closureDef(anon @ DefDef(_, List(List(param)), _, _)) = tree anon.rhs match { case PartialFunctionRHS(pf) => val anonSym = anon.symbol @@ -156,7 +156,7 @@ class ExpandSAMs extends MiniPhase: } def applyOrElseRhs(paramRefss: List[List[Tree]])(using Context) = { - val List(paramRef, defaultRef) = paramRefss.head + val List(paramRef, defaultRef) = paramRefss(1) def translateCase(cdef: CaseDef) = cdef.changeOwner(anonSym, applyOrElseFn) val defaultValue = defaultRef.select(nme.apply).appliedTo(paramRef) diff --git a/compiler/src/dotty/tools/dotc/transform/FirstTransform.scala b/compiler/src/dotty/tools/dotc/transform/FirstTransform.scala index 3f6693440207..12e85793205b 100644 --- a/compiler/src/dotty/tools/dotc/transform/FirstTransform.scala +++ b/compiler/src/dotty/tools/dotc/transform/FirstTransform.scala @@ -117,17 +117,14 @@ class FirstTransform extends MiniPhase with InfoTransformer { thisPhase => override def transformTemplate(impl: Template)(using Context): Tree = cpy.Template(impl)(self = EmptyValDef) - override def transformDefDef(ddef: DefDef)(using Context): Tree = { + override def transformDefDef(ddef: DefDef)(using Context): Tree = val meth = ddef.symbol.asTerm - if (meth.hasAnnotation(defn.NativeAnnot)) { + if meth.hasAnnotation(defn.NativeAnnot) then meth.resetFlag(Deferred) - polyDefDef(meth, - _ => _ => ref(defn.Sys_error.termRef).withSpan(ddef.span) + DefDef(meth, _ => + ref(defn.Sys_error.termRef).withSpan(ddef.span) .appliedTo(Literal(Constant(s"native method stub")))) - } - else ddef - } override def transformStats(trees: List[Tree])(using Context): List[Tree] = ast.Trees.flatten(atPhase(thisPhase.next)(reorderAndComplete(trees))) diff --git a/compiler/src/dotty/tools/dotc/transform/FullParameterization.scala b/compiler/src/dotty/tools/dotc/transform/FullParameterization.scala index fa8e39eb6c1e..93f72199617e 100644 --- a/compiler/src/dotty/tools/dotc/transform/FullParameterization.scala +++ b/compiler/src/dotty/tools/dotc/transform/FullParameterization.scala @@ -136,8 +136,9 @@ trait FullParameterization { */ private def allInstanceTypeParams(originalDef: DefDef, abstractOverClass: Boolean)(using Context): List[Symbol] = if (abstractOverClass) - originalDef.tparams.map(_.symbol) ::: originalDef.symbol.enclosingClass.typeParams - else originalDef.tparams.map(_.symbol) + originalDef.leadingTypeParams.map(_.symbol) ::: originalDef.symbol.enclosingClass.typeParams + else + originalDef.leadingTypeParams.map(_.symbol) /** Given an instance method definition `originalDef`, return a * fully parameterized method definition derived from `originalDef`, which @@ -147,11 +148,12 @@ trait FullParameterization { * of class that contained original defDef */ def fullyParameterizedDef(derived: TermSymbol, originalDef: DefDef, abstractOverClass: Boolean = true)(using Context): Tree = - polyDefDef(derived, trefs => vrefss => { + DefDef(derived, prefss => { + val (trefs, vrefss) = splitArgs(prefss) val origMeth = originalDef.symbol val origClass = origMeth.enclosingClass.asClass - val origTParams = allInstanceTypeParams(originalDef, abstractOverClass) - val origVParams = originalDef.vparamss.flatten map (_.symbol) + val origLeadingTypeParamSyms = allInstanceTypeParams(originalDef, abstractOverClass) + val origOtherParamSyms = originalDef.trailingParamss.flatten.map(_.symbol) val thisRef :: argRefs = vrefss.flatten /** If tree should be rewired, the rewired tree, otherwise EmptyTree. @@ -204,7 +206,7 @@ trait FullParameterization { new TreeTypeMap( typeMap = rewireType(_) - .subst(origTParams ++ origVParams, trefs ++ argRefs.map(_.tpe)) + .subst(origLeadingTypeParamSyms ++ origOtherParamSyms, (trefs ++ argRefs).tpes) .substThisUnlessStatic(origClass, thisRef.tpe), treeMap = { case tree: This if tree.symbol == origClass => thisRef @@ -221,25 +223,25 @@ trait FullParameterization { * - the value parameters of the original method `originalDef`. */ def forwarder(derived: TermSymbol, originalDef: DefDef, abstractOverClass: Boolean = true, liftThisType: Boolean = false)(using Context): Tree = { - val fun = + val fun: Tree = ref(derived.termRef) .appliedToTypes(allInstanceTypeParams(originalDef, abstractOverClass).map(_.typeRef)) .appliedTo(This(originalDef.symbol.enclosingClass.asClass)) - - (if (!liftThisType) - fun.appliedToArgss(originalDef.vparamss.nestedMap(vparam => ref(vparam.symbol))) - else { - // this type could have changed on forwarding. Need to insert a cast. - originalDef.vparamss.foldLeft(fun)((acc, vparams) => { + val fwd = + if !liftThisType then + fun.appliedToArgss(originalDef.trailingParamss.nestedMap(param => ref(param.symbol))) + else + // this type could have changed on forwarding. Need to insert a cast. + originalDef.trailingParamss.foldLeft(fun)((acc, params) => { val meth = acc.tpe.asInstanceOf[MethodType] - val paramTypes = meth.instantiateParamInfos(vparams.map(_.tpe)) + val paramTypes = meth.instantiateParamInfos(params.tpes) acc.appliedToArgs( - vparams.lazyZip(paramTypes).map((vparam, paramType) => { - assert(vparam.tpe <:< paramType.widen) // type should still conform to widened type - ref(vparam.symbol).ensureConforms(paramType) + params.lazyZip(paramTypes).map((param, paramType) => { + assert(param.tpe <:< paramType.widen) // type should still conform to widened type + ref(param.symbol).ensureConforms(paramType) })) - }) - }).withSpan(originalDef.rhs.span) + }) + fwd.withSpan(originalDef.rhs.span) } } diff --git a/compiler/src/dotty/tools/dotc/transform/FunctionXXLForwarders.scala b/compiler/src/dotty/tools/dotc/transform/FunctionXXLForwarders.scala index 3ef0debb93e0..4fd075aa0dba 100644 --- a/compiler/src/dotty/tools/dotc/transform/FunctionXXLForwarders.scala +++ b/compiler/src/dotty/tools/dotc/transform/FunctionXXLForwarders.scala @@ -34,7 +34,7 @@ class FunctionXXLForwarders extends MiniPhase with IdentityDenotTransformer { var idx = -1 val argss = receiver.tpe.widenDealias.paramInfoss.map(_.map { param => idx += 1 - argsApply.appliedToArgs(List(Literal(Constant(idx)))).cast(param) + argsApply.appliedToTermArgs(List(Literal(Constant(idx)))).cast(param) }) ref(receiver.symbol).appliedToArgss(argss).cast(defn.ObjectType) } diff --git a/compiler/src/dotty/tools/dotc/transform/HoistSuperArgs.scala b/compiler/src/dotty/tools/dotc/transform/HoistSuperArgs.scala index 851d65a1fcfc..219e51050961 100644 --- a/compiler/src/dotty/tools/dotc/transform/HoistSuperArgs.scala +++ b/compiler/src/dotty/tools/dotc/transform/HoistSuperArgs.scala @@ -129,8 +129,9 @@ class HoistSuperArgs extends MiniPhase with IdentityDenotTransformer { thisPhase cpy.Apply(arg)(fn, hoistSuperArg(arg1, cdef) :: Nil) case _ if arg.existsSubTree(needsHoist) => val superMeth = newSuperArgMethod(arg.tpe) - val superArgDef = polyDefDef(superMeth, trefs => vrefss => { - val paramSyms = trefs.map(_.typeSymbol) ::: vrefss.flatten.map(_.symbol) + val superArgDef = DefDef(superMeth, prefss => { + val paramSyms = prefss.flatten.map(pref => + if pref.isType then pref.tpe.typeSymbol else pref.symbol) val tmap = new TreeTypeMap( typeMap = new TypeMap { lazy val origToParam = origParams.zip(paramSyms).toMap diff --git a/compiler/src/dotty/tools/dotc/transform/InlinePatterns.scala b/compiler/src/dotty/tools/dotc/transform/InlinePatterns.scala index e86b8e5f3f89..fdef553a835d 100644 --- a/compiler/src/dotty/tools/dotc/transform/InlinePatterns.scala +++ b/compiler/src/dotty/tools/dotc/transform/InlinePatterns.scala @@ -56,6 +56,6 @@ class InlinePatterns extends MiniPhase: fn match case Block(TypeDef(_, template: Template) :: Nil, Apply(Select(New(_),_), Nil)) if template.constr.rhs.isEmpty => template.body match - case List(ddef @ DefDef(`name`, _, _, _, _)) => BetaReduce(ddef, args) + case List(ddef @ DefDef(`name`, _, _, _)) => BetaReduce(ddef, args) case _ => tree case _ => tree diff --git a/compiler/src/dotty/tools/dotc/transform/InterceptedMethods.scala b/compiler/src/dotty/tools/dotc/transform/InterceptedMethods.scala index eaa77ff56c6c..0b42162643f8 100644 --- a/compiler/src/dotty/tools/dotc/transform/InterceptedMethods.scala +++ b/compiler/src/dotty/tools/dotc/transform/InterceptedMethods.scala @@ -73,7 +73,7 @@ class InterceptedMethods extends MiniPhase { } if tree.fun.symbol == defn.Any_!= then - qual.select(defn.Any_==).appliedToArgs(tree.args).select(defn.Boolean_!).withSpan(tree.span) + qual.select(defn.Any_==).appliedToTermArgs(tree.args).select(defn.Boolean_!).withSpan(tree.span) else tree } diff --git a/compiler/src/dotty/tools/dotc/transform/LambdaLift.scala b/compiler/src/dotty/tools/dotc/transform/LambdaLift.scala index e8791efeb97c..2409d0f94815 100644 --- a/compiler/src/dotty/tools/dotc/transform/LambdaLift.scala +++ b/compiler/src/dotty/tools/dotc/transform/LambdaLift.scala @@ -236,7 +236,7 @@ object LambdaLift { // the free variables of the class. symSet(called, sym) += sym.owner - tree.vparamss.head.find(_.name == nme.OUTER) match { + tree.termParamss.head.find(_.name == nme.OUTER) match { case Some(vdef) => outerParam(sym) = vdef.symbol case _ => } @@ -454,7 +454,7 @@ object LambdaLift { tree match { case tree: DefDef => cpy.DefDef(tree)( - vparamss = tree.vparamss.map(freeParamDefs ++ _), + paramss = tree.termParamss.map(freeParamDefs ++ _), rhs = if (sym.isPrimaryConstructor && !sym.owner.is(Trait)) copyParams(tree.rhs) else tree.rhs) diff --git a/compiler/src/dotty/tools/dotc/transform/MegaPhase.scala b/compiler/src/dotty/tools/dotc/transform/MegaPhase.scala index 385d02638b9f..77671fc6498c 100644 --- a/compiler/src/dotty/tools/dotc/transform/MegaPhase.scala +++ b/compiler/src/dotty/tools/dotc/transform/MegaPhase.scala @@ -243,11 +243,11 @@ class MegaPhase(val miniPhases: Array[MiniPhase]) extends Phase { case tree: DefDef => inContext(prepDefDef(tree, start)(using outerCtx)) { def mapDefDef(using Context) = { - val tparams = transformSpecificTrees(tree.tparams, start) - val vparamss = tree.vparamss.mapConserve(transformSpecificTrees(_, start)) + val paramss = tree.paramss.mapConserve(transformSpecificTrees(_, start)) + .asInstanceOf[List[ParamClause]] val tpt = transformTree(tree.tpt, start) val rhs = transformTree(tree.rhs, start) - cpy.DefDef(tree)(tree.name, tparams, vparamss, tpt, rhs) + cpy.DefDef(tree)(tree.name, paramss, tpt, rhs) } goDefDef(inLocalContext(mapDefDef), start) } diff --git a/compiler/src/dotty/tools/dotc/transform/Memoize.scala b/compiler/src/dotty/tools/dotc/transform/Memoize.scala index fa5f97c2ae25..2f73ed8bd9eb 100644 --- a/compiler/src/dotty/tools/dotc/transform/Memoize.scala +++ b/compiler/src/dotty/tools/dotc/transform/Memoize.scala @@ -185,8 +185,9 @@ class Memoize extends MiniPhase with IdentityDenotTransformer { thisPhase => field.setFlag(Mutable) myState.classesThatNeedReleaseFence += sym.owner val initializer = - if (isErasableBottomField(field, tree.vparamss.head.head.tpt.tpe.classSymbol)) Literal(Constant(())) - else Assign(ref(field), adaptToField(field, ref(tree.vparamss.head.head.symbol))) + if isErasableBottomField(field, tree.termParamss.head.head.tpt.tpe.classSymbol) + then Literal(Constant(())) + else Assign(ref(field), adaptToField(field, ref(tree.termParamss.head.head.symbol))) val setterDef = cpy.DefDef(tree)(rhs = transformFollowingDeep(initializer)(using ctx.withOwner(sym))) removeUnwantedAnnotations(sym, defn.SetterMetaAnnot) setterDef diff --git a/compiler/src/dotty/tools/dotc/transform/Mixin.scala b/compiler/src/dotty/tools/dotc/transform/Mixin.scala index c3ff36f3e5cb..fc335b66a25c 100644 --- a/compiler/src/dotty/tools/dotc/transform/Mixin.scala +++ b/compiler/src/dotty/tools/dotc/transform/Mixin.scala @@ -216,7 +216,7 @@ class Mixin extends MiniPhase with SymTransformer { thisPhase => case _ => val Apply(sel @ Select(New(_), nme.CONSTRUCTOR), args) = tree val (callArgs, initArgs) = if (tree.symbol.owner.is(Trait)) (Nil, args) else (args, Nil) - (superRef(tree.symbol, tree.span).appliedToArgs(callArgs), Nil, initArgs) + (superRef(tree.symbol, tree.span).appliedToTermArgs(callArgs), Nil, initArgs) } val superCallsAndArgs: Map[Symbol, (Tree, List[Tree], List[Tree])] = ( @@ -285,12 +285,12 @@ class Mixin extends MiniPhase with SymTransformer { thisPhase => for (meth <- mixin.info.decls.toList if needsMixinForwarder(meth)) yield { util.Stats.record("mixin forwarders") - transformFollowing(polyDefDef(mkForwarderSym(meth.asTerm, Bridge), forwarderRhsFn(meth))) + transformFollowing(DefDef(mkForwarderSym(meth.asTerm, Bridge), forwarderRhsFn(meth))) } cpy.Template(impl)( constr = - if (cls.is(Trait)) cpy.DefDef(impl.constr)(vparamss = Nil :: Nil) + if (cls.is(Trait)) cpy.DefDef(impl.constr)(paramss = Nil :: Nil) else impl.constr, parents = impl.parents.map(p => TypeTree(p.tpe).withSpan(p.span)), body = diff --git a/compiler/src/dotty/tools/dotc/transform/MixinOps.scala b/compiler/src/dotty/tools/dotc/transform/MixinOps.scala index a563f6eabe03..ff73705645a4 100644 --- a/compiler/src/dotty/tools/dotc/transform/MixinOps.scala +++ b/compiler/src/dotty/tools/dotc/transform/MixinOps.scala @@ -74,22 +74,20 @@ class MixinOps(cls: ClassSymbol, thisPhase: DenotTransformer)(using Context) { isCurrent(meth) } - final val PrivateOrAccessor: FlagSet = Private | Accessor final val PrivateOrAccessorOrDeferred: FlagSet = Private | Accessor | Deferred - def forwarderRhsFn(target: Symbol): List[Type] => List[List[Tree]] => Tree = { - targs => vrefss => - val tapp = superRef(target).appliedToTypes(targs) - vrefss match { + def forwarderRhsFn(target: Symbol): List[List[Tree]] => Tree = + prefss => + val (targs, vargss) = splitArgs(prefss) + val tapp = superRef(target).appliedToTypeTrees(targs) + vargss match case Nil | List(Nil) => // Overriding is somewhat loose about `()T` vs `=> T`, so just pick // whichever makes sense for `target` tapp.ensureApplied case _ => - tapp.appliedToArgss(vrefss) - } - } + tapp.appliedToArgss(vargss) private def competingMethodsIterator(meth: Symbol): Iterator[Symbol] = cls.baseClasses.iterator diff --git a/compiler/src/dotty/tools/dotc/transform/PatternMatcher.scala b/compiler/src/dotty/tools/dotc/transform/PatternMatcher.scala index 1be6bbda98fb..169f68e2cad9 100644 --- a/compiler/src/dotty/tools/dotc/transform/PatternMatcher.scala +++ b/compiler/src/dotty/tools/dotc/transform/PatternMatcher.scala @@ -390,7 +390,7 @@ object PatternMatcher { case mt: MethodType => assert(mt.isImplicitMethod) val (args, rest) = implicits.splitAt(mt.paramNames.size) - applyImplicits(acc.appliedToArgs(args), rest, mt.resultType) + applyImplicits(acc.appliedToTermArgs(args), rest, mt.resultType) case _ => assert(implicits.isEmpty) acc diff --git a/compiler/src/dotty/tools/dotc/transform/PickleQuotes.scala b/compiler/src/dotty/tools/dotc/transform/PickleQuotes.scala index cb1ffa478d70..0f00add41809 100644 --- a/compiler/src/dotty/tools/dotc/transform/PickleQuotes.scala +++ b/compiler/src/dotty/tools/dotc/transform/PickleQuotes.scala @@ -166,7 +166,7 @@ class PickleQuotes extends MacroTransform { val literalValue = if lit.const.tag == Constants.NullTag || lit.const.tag == Constants.UnitTag then Nil else List(body) - val constant = reflect.select(s"${typeName}Constant".toTermName).select(nme.apply).appliedToArgs(literalValue) + val constant = reflect.select(s"${typeName}Constant".toTermName).select(nme.apply).appliedToTermArgs(literalValue) val literal = reflect.select("Literal".toTermName).select(nme.apply).appliedTo(constant) reflect.select("TreeMethods".toTermName).select("asExpr".toTermName).appliedTo(literal).asInstance(exprType) } diff --git a/compiler/src/dotty/tools/dotc/transform/ResolveSuper.scala b/compiler/src/dotty/tools/dotc/transform/ResolveSuper.scala index 9e3d3c2c3b85..30ccc69e37ca 100644 --- a/compiler/src/dotty/tools/dotc/transform/ResolveSuper.scala +++ b/compiler/src/dotty/tools/dotc/transform/ResolveSuper.scala @@ -49,7 +49,7 @@ class ResolveSuper extends MiniPhase with IdentityDenotTransformer { thisPhase = for (superAcc <- mixin.info.decls.filter(_.isSuperAccessor)) yield { util.Stats.record("super accessors") - polyDefDef(mkForwarderSym(superAcc.asTerm), forwarderRhsFn(rebindSuper(cls, superAcc))) + DefDef(mkForwarderSym(superAcc.asTerm), forwarderRhsFn(rebindSuper(cls, superAcc))) } val overrides = mixins.flatMap(superAccessors) @@ -64,7 +64,7 @@ class ResolveSuper extends MiniPhase with IdentityDenotTransformer { thisPhase = val cls = meth.owner.asClass val ops = new MixinOps(cls, thisPhase) import ops._ - polyDefDef(meth, forwarderRhsFn(rebindSuper(cls, meth))) + DefDef(meth, forwarderRhsFn(rebindSuper(cls, meth))) } else ddef } diff --git a/compiler/src/dotty/tools/dotc/transform/SpecializeFunctions.scala b/compiler/src/dotty/tools/dotc/transform/SpecializeFunctions.scala index ace121e1b016..91555dc2b995 100644 --- a/compiler/src/dotty/tools/dotc/transform/SpecializeFunctions.scala +++ b/compiler/src/dotty/tools/dotc/transform/SpecializeFunctions.scala @@ -23,8 +23,8 @@ class SpecializeFunctions extends MiniPhase { */ override def transformDefDef(ddef: DefDef)(using Context) = { if ddef.name != nme.apply - || ddef.vparamss.length != 1 - || ddef.vparamss.head.length > 2 + || ddef.termParamss.length != 1 + || ddef.termParamss.head.length > 2 || !ctx.owner.isClass then return ddef @@ -35,7 +35,7 @@ class SpecializeFunctions extends MiniPhase { var specName: Name = null def isSpecializable = { - val paramTypes = ddef.vparamss.head.map(_.symbol.info) + val paramTypes = ddef.termParamss.head.map(_.symbol.info) val retType = sym.info.finalResultType specName = nme.apply.specializedFunction(retType, paramTypes) defn.isSpecializableFunction(cls, paramTypes, retType) @@ -54,12 +54,12 @@ class SpecializeFunctions extends MiniPhase { DefDef(specializedApply.asTerm, vparamss => { ddef.rhs .changeOwner(ddef.symbol, specializedApply) - .subst(ddef.vparamss.head.map(_.symbol), vparamss.head.map(_.symbol)) + .subst(ddef.termParamss.head.map(_.symbol), vparamss.head.map(_.symbol)) }) // create a forwarding to the specialized apply - val args = ddef.vparamss.head.map(vparam => ref(vparam.symbol)) - val rhs = This(cls).select(specializedApply).appliedToArgs(args) + val args = ddef.termParamss.head.map(vparam => ref(vparam.symbol)) + val rhs = This(cls).select(specializedApply).appliedToTermArgs(args) val ddef1 = cpy.DefDef(ddef)(rhs = rhs) Thicket(ddef1, specializedDecl) } @@ -92,7 +92,7 @@ class SpecializeFunctions extends MiniPhase { } } - newSel.appliedToArgs(args) + newSel.appliedToTermArgs(args) case _ => tree } diff --git a/compiler/src/dotty/tools/dotc/transform/Splicer.scala b/compiler/src/dotty/tools/dotc/transform/Splicer.scala index fdf704dc63d7..66419c8c2006 100644 --- a/compiler/src/dotty/tools/dotc/transform/Splicer.scala +++ b/compiler/src/dotty/tools/dotc/transform/Splicer.scala @@ -175,7 +175,7 @@ object Splicer { } def checkIfValidStaticCall(tree: Tree)(using Env): Unit = tree match { - case closureDef(ddef @ DefDef(_, Nil, (ev :: Nil) :: Nil, _, _)) if ddef.symbol.info.isContextualMethod => + case closureDef(ddef @ DefDef(_, ValDefs(ev :: Nil) :: Nil, _, _)) if ddef.symbol.info.isContextualMethod => checkIfValidStaticCall(ddef.rhs)(using summon[Env] + ev.symbol) case Block(stats, expr) => @@ -265,7 +265,7 @@ object Splicer { else unexpectedTree(tree) - case closureDef((ddef @ DefDef(_, _, (arg :: Nil) :: Nil, _, _))) => + case closureDef((ddef @ DefDef(_, ValDefs(arg :: Nil) :: Nil, _, _))) => (obj: AnyRef) => interpretTree(ddef.rhs)(using env.updated(arg.symbol, obj)) // Interpret `foo(j = x, i = y)` which it is expanded to diff --git a/compiler/src/dotty/tools/dotc/transform/SyntheticMembers.scala b/compiler/src/dotty/tools/dotc/transform/SyntheticMembers.scala index 22841a5cf1a0..3302e5faa412 100644 --- a/compiler/src/dotty/tools/dotc/transform/SyntheticMembers.scala +++ b/compiler/src/dotty/tools/dotc/transform/SyntheticMembers.scala @@ -117,7 +117,7 @@ class SyntheticMembers(thisPhase: DenotTransformer) { coord = clazz.coord).enteredAfter(thisPhase).asTerm def forwardToRuntime(vrefs: List[Tree]): Tree = - ref(defn.runtimeMethodRef("_" + sym.name.toString)).appliedToArgs(This(clazz) :: vrefs) + ref(defn.runtimeMethodRef("_" + sym.name.toString)).appliedToTermArgs(This(clazz) :: vrefs) def ownName: Tree = Literal(Constant(clazz.name.stripModuleClassSuffix.toString)) diff --git a/compiler/src/dotty/tools/dotc/transform/TailRec.scala b/compiler/src/dotty/tools/dotc/transform/TailRec.scala index 10841bf552c9..9330016f3292 100644 --- a/compiler/src/dotty/tools/dotc/transform/TailRec.scala +++ b/compiler/src/dotty/tools/dotc/transform/TailRec.scala @@ -140,7 +140,7 @@ class TailRec extends MiniPhase { // than first one will collect info about which transformations and rewritings should be applied // and second one will actually apply, // now this speculatively transforms tree and throws away result in many cases - val transformer = new TailRecElimination(method, enclosingClass, tree.vparamss.head.map(_.symbol), mandatory) + val transformer = new TailRecElimination(method, enclosingClass, tree.termParamss.head.map(_.symbol), mandatory) val rhsSemiTransformed = transformer.transform(tree.rhs) if (transformer.rewrote) { diff --git a/compiler/src/dotty/tools/dotc/transform/TreeChecker.scala b/compiler/src/dotty/tools/dotc/transform/TreeChecker.scala index 68d15b82e362..7eaad36b18a2 100644 --- a/compiler/src/dotty/tools/dotc/transform/TreeChecker.scala +++ b/compiler/src/dotty/tools/dotc/transform/TreeChecker.scala @@ -442,7 +442,7 @@ class TreeChecker extends Phase with SymTransformer { val decls = cls.classInfo.decls.toList.toSet.filter(isNonMagicalMember) val defined = impl.body.map(_.symbol) - + def isAllowed(sym: Symbol): Boolean = sym.is(ConstructorProxy) && !ctx.phase.erasedTypes @@ -457,30 +457,27 @@ class TreeChecker extends Phase with SymTransformer { } override def typedDefDef(ddef: untpd.DefDef, sym: Symbol)(using Context): Tree = - def defParamss = - (ddef.tparams :: ddef.vparamss).filter(!_.isEmpty).map(_.map(_.symbol)) + def defParamss = ddef.paramss.filter(!_.isEmpty).nestedMap(_.symbol) def layout(symss: List[List[Symbol]]): String = symss.map(syms => i"($syms%, %)").mkString assert(ctx.erasedTypes || sym.rawParamss == defParamss, i"""param mismatch for ${sym.showLocated}: |defined in tree = ${layout(defParamss)} |stored in symbol = ${layout(sym.rawParamss)}""") - withDefinedSyms(ddef.tparams) { - withDefinedSyms(ddef.vparamss.flatten) { - if (!sym.isClassConstructor && !(sym.name eq nme.STATIC_CONSTRUCTOR)) - assert(isValidJVMMethodName(sym.name.encode), s"${sym.name.debugString} name is invalid on jvm") - - ddef.vparamss.foreach(_.foreach { vparam => - assert(vparam.symbol.is(Param), - s"Parameter ${vparam.symbol} of ${sym.fullName} does not have flag `Param` set") - assert(!vparam.symbol.isOneOf(AccessFlags), - s"Parameter ${vparam.symbol} of ${sym.fullName} has invalid flag(s): ${(vparam.symbol.flags & AccessFlags).flagsString}") - }) - - val tpdTree = super.typedDefDef(ddef, sym) - assert(isMethodType(sym.info), i"wrong type, expect a method type for ${sym.fullName}, but found: ${sym.info}") - tpdTree - } + withDefinedSyms(ddef.paramss.flatten) { + if (!sym.isClassConstructor && !(sym.name eq nme.STATIC_CONSTRUCTOR)) + assert(isValidJVMMethodName(sym.name.encode), s"${sym.name.debugString} name is invalid on jvm") + + ddef.termParamss.foreach(_.foreach { vparam => + assert(vparam.symbol.is(Param), + s"Parameter ${vparam.symbol} of ${sym.fullName} does not have flag `Param` set") + assert(!vparam.symbol.isOneOf(AccessFlags), + s"Parameter ${vparam.symbol} of ${sym.fullName} has invalid flag(s): ${(vparam.symbol.flags & AccessFlags).flagsString}") + }) + + val tpdTree = super.typedDefDef(ddef, sym) + assert(isMethodType(sym.info), i"wrong type, expect a method type for ${sym.fullName}, but found: ${sym.info}") + tpdTree } override def typedCase(tree: untpd.CaseDef, sel: Tree, selType: Type, pt: Type)(using Context): CaseDef = diff --git a/compiler/src/dotty/tools/dotc/transform/TupleOptimizations.scala b/compiler/src/dotty/tools/dotc/transform/TupleOptimizations.scala index 124581c1db6e..038ce8985996 100644 --- a/compiler/src/dotty/tools/dotc/transform/TupleOptimizations.scala +++ b/compiler/src/dotty/tools/dotc/transform/TupleOptimizations.scala @@ -49,7 +49,7 @@ class TupleOptimizations extends MiniPhase with IdentityDenotTransformer { else { // val it = Iterator.single(head) ++ tail.asInstanceOf[Product].productIterator // TupleN+1(it.next(), ..., it.next()) - val fullIterator = ref(defn.RuntimeTuple_consIterator).appliedToArgs(head :: tail :: Nil) + val fullIterator = ref(defn.RuntimeTuple_consIterator).appliedToTermArgs(head :: tail :: Nil) evalOnce(fullIterator) { it => knownTupleFromIterator(tpes.length, it).asInstance(tree.tpe) } @@ -127,7 +127,7 @@ class TupleOptimizations extends MiniPhase with IdentityDenotTransformer { else { // val it = self.asInstanceOf[Product].productIterator ++ that.asInstanceOf[Product].productIterator // TupleN+M(it.next(), ..., it.next()) - val fullIterator = ref(defn.RuntimeTuple_concatIterator).appliedToArgs(tree.args) + val fullIterator = ref(defn.RuntimeTuple_concatIterator).appliedToTermArgs(tree.args) evalOnce(fullIterator) { it => knownTupleFromIterator(n + m, it).asInstance(tree.tpe) } @@ -192,7 +192,7 @@ class TupleOptimizations extends MiniPhase with IdentityDenotTransformer { val size = elements.size assert(0 < size && size <= MaxTupleArity) val tupleModule = defn.TupleType(size).classSymbol.companionModule - ref(tupleModule).select(nme.apply).appliedToTypes(tpes).appliedToArgs(elements) + ref(tupleModule).select(nme.apply).appliedToTypes(tpes).appliedToTermArgs(elements) } private def knownTupleFromIterator(size: Int, it: Tree)(using Context): Tree = diff --git a/compiler/src/dotty/tools/dotc/transform/UncacheGivenAliases.scala b/compiler/src/dotty/tools/dotc/transform/UncacheGivenAliases.scala index e5d5bf4b3931..958fce04da77 100644 --- a/compiler/src/dotty/tools/dotc/transform/UncacheGivenAliases.scala +++ b/compiler/src/dotty/tools/dotc/transform/UncacheGivenAliases.scala @@ -59,7 +59,7 @@ class UncacheGivenAliases extends MiniPhase with IdentityDenotTransformer: initFlags = sym.flags &~ Lazy | Method, info = ExprType(sym.info)) .installAfter(thisPhase) - cpy.DefDef(tree)(tree.name, Nil, Nil, tree.tpt, tree.rhs) + cpy.DefDef(tree)(tree.name, Nil, tree.tpt, tree.rhs) else tree end UncacheGivenAliases diff --git a/compiler/src/dotty/tools/dotc/transform/init/Checking.scala b/compiler/src/dotty/tools/dotc/transform/init/Checking.scala index 90741d86124f..6a8007e06516 100644 --- a/compiler/src/dotty/tools/dotc/transform/init/Checking.scala +++ b/compiler/src/dotty/tools/dotc/transform/init/Checking.scala @@ -130,16 +130,13 @@ object Checking { tpl.parents.foreach { case tree @ Block(_, parent) => - val (ctor, _, _) = decomposeCall(parent) - checkConstructor(ctor.symbol, parent.tpe, tree) + checkConstructor(funPart(parent).symbol, parent.tpe, tree) case tree @ Apply(Block(_, parent), _) => - val (ctor, _, _) = decomposeCall(parent) - checkConstructor(ctor.symbol, tree.tpe, tree) + checkConstructor(funPart(parent).symbol, tree.tpe, tree) case parent : Apply => - val (ctor, _, argss) = decomposeCall(parent) - checkConstructor(ctor.symbol, parent.tpe, parent) + checkConstructor(funPart(parent).symbol, parent.tpe, parent) case ref => val cls = ref.tpe.classSymbol.asClass diff --git a/compiler/src/dotty/tools/dotc/transform/init/Summarization.scala b/compiler/src/dotty/tools/dotc/transform/init/Summarization.scala index 82293c63452e..258900311d3e 100644 --- a/compiler/src/dotty/tools/dotc/transform/init/Summarization.scala +++ b/compiler/src/dotty/tools/dotc/transform/init/Summarization.scala @@ -292,16 +292,16 @@ object Summarization { val effsAll = tpl.parents.foldLeft(effs) { (effs, parent) => effs ++ (parent match { case tree @ Block(stats, parent) => - val (ctor @ Select(qual, _), _, argss) = decomposeCall(parent) - parentArgEffsWithInit(qual :: stats ++ argss.flatten, ctor.symbol, tree) + val ctor @ Select(qual, _) = funPart(parent) + parentArgEffsWithInit(qual :: stats ++ termArgss(parent).flatten, ctor.symbol, tree) case tree @ Apply(Block(stats, parent), args) => - val (ctor @ Select(qual, _), _, argss) = decomposeCall(parent) - parentArgEffsWithInit(qual :: stats ++ args ++ argss.flatten, ctor.symbol, tree) + val ctor @ Select(qual, _) = funPart(parent) + parentArgEffsWithInit(qual :: stats ++ args ++ termArgss(parent).flatten, ctor.symbol, tree) case parent : Apply => - val (ctor @ Select(qual, _), _, argss) = decomposeCall(parent) - parentArgEffsWithInit(qual :: argss.flatten, ctor.symbol, parent) + val ctor @ Select(qual, _) = funPart(parent) + parentArgEffsWithInit(qual :: termArgss(parent).flatten, ctor.symbol, parent) case ref => val tref: TypeRef = ref.tpe.typeConstructor.asInstanceOf diff --git a/compiler/src/dotty/tools/dotc/transform/localopt/StringInterpolatorOpt.scala b/compiler/src/dotty/tools/dotc/transform/localopt/StringInterpolatorOpt.scala index e0a565737fff..a1c1708302f2 100644 --- a/compiler/src/dotty/tools/dotc/transform/localopt/StringInterpolatorOpt.scala +++ b/compiler/src/dotty/tools/dotc/transform/localopt/StringInterpolatorOpt.scala @@ -152,13 +152,13 @@ class StringInterpolatorOpt extends MiniPhase { val stringToString = defn.StringContextModule_processEscapes.info.asInstanceOf[MethodType] val process = tpd.Lambda(stringToString, args => - if (isRaw) args.head else ref(defn.StringContextModule_processEscapes).appliedToArgs(args)) + if (isRaw) args.head else ref(defn.StringContextModule_processEscapes).appliedToTermArgs(args)) evalOnce(pre) { sc => val parts = sc.select(defn.StringContext_parts) ref(defn.StringContextModule_standardInterpolator) - .appliedToArgs(List(process, args, parts)) + .appliedToTermArgs(List(process, args, parts)) } } else diff --git a/compiler/src/dotty/tools/dotc/transform/patmat/Space.scala b/compiler/src/dotty/tools/dotc/transform/patmat/Space.scala index a231dfe8d955..9d11ffb5a961 100644 --- a/compiler/src/dotty/tools/dotc/transform/patmat/Space.scala +++ b/compiler/src/dotty/tools/dotc/transform/patmat/Space.scala @@ -388,7 +388,7 @@ class SpaceEngine(using Context) extends SpaceLogic { projectSeq(pats) case UnApply(fun, _, pats) => - val (fun1, _, _) = decomposeCall(fun) + val fun1 = funPart(fun) val funRef = fun1.tpe.asInstanceOf[TermRef] if (fun.symbol.name == nme.unapplySeq) if (fun.symbol.owner == scalaSeqFactoryClass) diff --git a/compiler/src/dotty/tools/dotc/transform/sjs/PrepJSExports.scala b/compiler/src/dotty/tools/dotc/transform/sjs/PrepJSExports.scala index fa2eca8c211d..8fe0083fb61f 100644 --- a/compiler/src/dotty/tools/dotc/transform/sjs/PrepJSExports.scala +++ b/compiler/src/dotty/tools/dotc/transform/sjs/PrepJSExports.scala @@ -439,8 +439,8 @@ object PrepJSExports { private def genProxyDefDef(clsSym: ClassSymbol, trgSym: Symbol, proxySym: TermSymbol, span: Span)(using Context): Tree = { - polyDefDef(proxySym, { targs => argss => - This(clsSym).select(trgSym).appliedToTypes(targs).appliedToArgss(argss) + DefDef(proxySym, { argss => + This(clsSym).select(trgSym).appliedToArgss(argss) }).withSpan(span) } diff --git a/compiler/src/dotty/tools/dotc/typer/Applications.scala b/compiler/src/dotty/tools/dotc/typer/Applications.scala index a388b7d55e22..0fc52dc5e88e 100644 --- a/compiler/src/dotty/tools/dotc/typer/Applications.scala +++ b/compiler/src/dotty/tools/dotc/typer/Applications.scala @@ -196,12 +196,8 @@ object Applications { def wrapDefs(defs: mutable.ListBuffer[Tree], tree: Tree)(using Context): Tree = if (defs != null && defs.nonEmpty) tpd.Block(defs.toList, tree) else tree - /** A wrapper indicating that its `app` argument has already integrated the type arguments - * of the expected type, provided that type is a (possibly ignored) PolyProto. - * I.e., if the expected type is a PolyProto, then `app` will be a `TypeApply(_, args)` where - * `args` are the type arguments of the expected type. - */ - class IntegratedTypeArgs(val app: Tree)(implicit @constructorOnly src: SourceFile) extends ProxyTree { + abstract class AppProxy(implicit @constructorOnly src: SourceFile) extends ProxyTree { + def app: Tree override def span = app.span def forwardTo = app @@ -210,27 +206,12 @@ object Applications { def productElement(n: Int): Any = app.productElement(n) } - /** The unapply method of this extractor also recognizes IntegratedTypeArgs in closure blocks. - * This is necessary to deal with closures as left arguments of extension method applications. - * A test case is i5606.scala - */ - object IntegratedTypeArgs { - def apply(app: Tree)(using Context) = new IntegratedTypeArgs(app) - def unapply(tree: Tree)(using Context): Option[Tree] = tree match { - case tree: IntegratedTypeArgs => Some(tree.app) - case Block(stats, IntegratedTypeArgs(app)) => Some(tpd.cpy.Block(tree)(stats, app)) - case _ => None - } - } - /** A wrapper indicating that its argument is an application of an extension method. */ - class ExtMethodApply(app: Tree)(implicit @constructorOnly src: SourceFile) - extends IntegratedTypeArgs(app) { - overwriteType(WildcardType) + class ExtMethodApply(val app: Tree)(implicit @constructorOnly src: SourceFile) extends AppProxy: + overwriteType(app.tpe) // ExtMethodApply always has wildcard type in order not to prompt any further adaptations // such as eta expansion before the method is fully applied. - } } trait Applications extends Compatibility { @@ -434,7 +415,7 @@ trait Applications extends Compatibility { /** Splice new method reference into existing application */ def spliceMeth(meth: Tree, app: Tree): Tree = app match { case Apply(fn, args) => - spliceMeth(meth, fn).appliedToArgs(args) + spliceMeth(meth, fn).appliedToTermArgs(args) case TypeApply(fn, targs) => // Note: It is important that the type arguments `targs` are passed in new trees // instead of being spliced in literally. Otherwise, a type argument to a default @@ -1060,8 +1041,6 @@ trait Applications extends Compatibility { val typedArgs = if (isNamed) typedNamedArgs(tree.args) else tree.args.mapconserve(typedType(_)) record("typedTypeApply") typedExpr(tree.fun, PolyProto(typedArgs, pt)) match { - case IntegratedTypeArgs(app) => - app case _: TypeApply if !ctx.isAfterTyper => errorTree(tree, "illegal repeated type application") case typedFn => @@ -1095,7 +1074,7 @@ trait Applications extends Compatibility { def newGenericArrayCall = ref(defn.DottyArraysModule) .select(defn.newGenericArrayMethod).withSpan(tree.span) - .appliedToTypeTrees(targs).appliedToArgs(args) + .appliedToTypeTrees(targs).appliedToTermArgs(args) if (TypeErasure.isGeneric(targ.tpe)) newGenericArrayCall @@ -1950,7 +1929,7 @@ trait Applications extends Compatibility { else val deepPt = pt.deepenProto deepPt match - case pt @ FunProto(_, resType: FunProto) => + case pt @ FunProto(_, resType: FunOrPolyProto) => // try to narrow further with snd argument list resolveMapped(candidates, skipParamClause(pt.typedArgs().tpes), resType) case _ => @@ -2146,9 +2125,6 @@ trait Applications extends Compatibility { // Always hide expected member to allow for chained extensions (needed for i6900.scala) case _: SelectionProto => (tree, IgnoredProto(currentPt)) - case PolyProto(targs, restpe) => - val tree1 = untpd.TypeApply(tree, targs.map(untpd.TypedSplice(_))) - normalizePt(tree1, restpe) case _ => (tree, currentPt) diff --git a/compiler/src/dotty/tools/dotc/typer/Checking.scala b/compiler/src/dotty/tools/dotc/typer/Checking.scala index 7bd92e991354..e2f160142e6d 100644 --- a/compiler/src/dotty/tools/dotc/typer/Checking.scala +++ b/compiler/src/dotty/tools/dotc/typer/Checking.scala @@ -1195,9 +1195,8 @@ trait Checking { if (stat.symbol.is(Case)) stat match { - case TypeDef(_, Template(DefDef(_, tparams, vparamss, _, _), parents, _, _)) => - tparams.foreach(check) - vparamss.foreach(_.foreach(check)) + case TypeDef(_, Template(DefDef(_, paramss, _, _), parents, _, _)) => + paramss.foreach(_.foreach(check)) parents.foreach(check) case vdef: ValDef => vdef.rhs match { @@ -1212,7 +1211,7 @@ trait Checking { stat match { case TypeDef(_, impl: Template) => for ((defaultGetter @ - DefDef(DefaultGetterName(nme.CONSTRUCTOR, _), _, _, _, _)) <- impl.body) + DefDef(DefaultGetterName(nme.CONSTRUCTOR, _), _, _, _)) <- impl.body) check(defaultGetter.rhs) case _ => } diff --git a/compiler/src/dotty/tools/dotc/typer/Deriving.scala b/compiler/src/dotty/tools/dotc/typer/Deriving.scala index a964e0326978..1218d2c10094 100644 --- a/compiler/src/dotty/tools/dotc/typer/Deriving.scala +++ b/compiler/src/dotty/tools/dotc/typer/Deriving.scala @@ -271,15 +271,17 @@ trait Deriving { import tpd._ /** The type class instance definition with symbol `sym` */ - def typeclassInstance(sym: Symbol)(using Context): List[Type] => (List[List[tpd.Tree]] => tpd.Tree) = { - (tparamRefs: List[Type]) => (paramRefss: List[List[tpd.Tree]]) => - val tparams = tparamRefs.map(_.typeSymbol.asType) - val params = if (paramRefss.isEmpty) Nil else paramRefss.head.map(_.symbol.asTerm) + def typeclassInstance(sym: Symbol)(using Context): List[List[tpd.Tree]] => tpd.Tree = + (paramRefss: List[List[tpd.Tree]]) => + val (tparamRefs, vparamRefss) = splitArgs(paramRefss) + val tparamTypes = tparamRefs.tpes + val tparams = tparamTypes.map(_.typeSymbol.asType) + val vparams = if (vparamRefss.isEmpty) Nil else vparamRefss.head.map(_.symbol.asTerm) tparams.foreach(ctx.enter(_)) - params.foreach(ctx.enter(_)) + vparams.foreach(ctx.enter(_)) def instantiated(info: Type): Type = info match { - case info: PolyType => instantiated(info.instantiate(tparamRefs)) - case info: MethodType => info.instantiate(params.map(_.termRef)) + case info: PolyType => instantiated(info.instantiate(tparamTypes)) + case info: MethodType => info.instantiate(vparams.map(_.termRef)) case info => info.widenExpr } def companionRef(tp: Type): TermRef = tp match { @@ -292,11 +294,11 @@ trait Deriving { val module = untpd.ref(companionRef(resultType)).withSpan(sym.span) val rhs = untpd.Select(module, nme.derived) typed(rhs, resultType) - } + end typeclassInstance def syntheticDef(sym: Symbol): Tree = inContext(ctx.fresh.setOwner(sym).setNewScope) { - if sym.is(Method) then tpd.polyDefDef(sym.asTerm, typeclassInstance(sym)) - else tpd.ValDef(sym.asTerm, typeclassInstance(sym)(Nil)(Nil)) + if sym.is(Method) then tpd.DefDef(sym.asTerm, typeclassInstance(sym)) + else tpd.ValDef(sym.asTerm, typeclassInstance(sym)(Nil)) } synthetics.map(syntheticDef).toList diff --git a/compiler/src/dotty/tools/dotc/typer/Dynamic.scala b/compiler/src/dotty/tools/dotc/typer/Dynamic.scala index 9ee5b43f9c93..355fcf4b42dc 100644 --- a/compiler/src/dotty/tools/dotc/typer/Dynamic.scala +++ b/compiler/src/dotty/tools/dotc/typer/Dynamic.scala @@ -160,10 +160,11 @@ trait Dynamic { * where c11, ..., cNn are the classOf constants representing the erasures of T11, ..., TNn. * * It's an error if U is neither a value nor a method type, or a dependent method - * type. + * type */ def handleStructural(tree: Tree)(using Context): Tree = { - val (fun @ Select(qual, name), targs, vargss) = decomposeCall(tree) + val fun @ Select(qual, name) = funPart(tree) + val vargss = termArgss(tree) def structuralCall(selectorName: TermName, classOfs: => List[Tree]) = { val selectable = adapt(qual, defn.SelectableClass.typeRef) diff --git a/compiler/src/dotty/tools/dotc/typer/ErrorReporting.scala b/compiler/src/dotty/tools/dotc/typer/ErrorReporting.scala index 3d50e4b3e519..be512af9a7c6 100644 --- a/compiler/src/dotty/tools/dotc/typer/ErrorReporting.scala +++ b/compiler/src/dotty/tools/dotc/typer/ErrorReporting.scala @@ -309,7 +309,7 @@ class ImplicitSearchError( // implicitly[Int => String] // found: x => f[Any](x) val call = tpd.closureBody(alt.tree) // the tree itself if not a closure - val (_, targs, _) = tpd.decomposeCall(call) + val targs = tpd.typeArgss(call).flatten val args = resolveTypes(targs)(using ctx.fresh.setTyperState(alt.tstate)) userDefinedErrorString(raw, params, args) } @@ -336,7 +336,8 @@ class ImplicitSearchError( */ private def userDefinedImplicitNotFoundParamMessage: Option[String] = paramSymWithMethodCallTree.flatMap { (sym, applTree) => userDefinedMsg(sym, defn.ImplicitNotFoundAnnot).map { rawMsg => - val (fn, targs, _) = tpd.decomposeCall(applTree) + val fn = tpd.funPart(applTree) + val targs = tpd.typeArgss(applTree).flatten val methodOwner = fn.symbol.owner val methodOwnerType = tpd.qualifier(fn).tpe val methodTypeParams = fn.symbol.paramSymss.flatten.filter(_.isType) diff --git a/compiler/src/dotty/tools/dotc/typer/Implicits.scala b/compiler/src/dotty/tools/dotc/typer/Implicits.scala index 58d009708e36..761d550afc96 100644 --- a/compiler/src/dotty/tools/dotc/typer/Implicits.scala +++ b/compiler/src/dotty/tools/dotc/typer/Implicits.scala @@ -937,7 +937,7 @@ trait Implicits: case Select(qual, _) => apply(x, qual) case Apply(fn, _) => apply(x, fn) case TypeApply(fn, _) => apply(x, fn) - case tree: Applications.IntegratedTypeArgs => apply(x, tree.app) + case tree: Applications.AppProxy => apply(x, tree.app) case _: This => false case _ => foldOver(x, tree) } diff --git a/compiler/src/dotty/tools/dotc/typer/Inferencing.scala b/compiler/src/dotty/tools/dotc/typer/Inferencing.scala index ef49574a46e7..d374ca7678e3 100644 --- a/compiler/src/dotty/tools/dotc/typer/Inferencing.scala +++ b/compiler/src/dotty/tools/dotc/typer/Inferencing.scala @@ -61,16 +61,15 @@ object Inferencing { ).process(tp) /** Instantiate any type variables in `tp` whose bounds contain a reference to - * one of the parameters in `tparams` or `vparamss`. + * one of the parameters in `paramss`. */ - def instantiateDependent(tp: Type, tparams: List[Symbol], vparamss: List[List[Symbol]])(using Context): Unit = { + def instantiateDependent(tp: Type, paramss: List[List[Symbol]])(using Context): Unit = { val dependentVars = new TypeAccumulator[Set[TypeVar]] { - @threadUnsafe lazy val params = (tparams :: vparamss).flatten def apply(tvars: Set[TypeVar], tp: Type) = tp match { case tp: TypeVar if !tp.isInstantiated && TypeComparer.bounds(tp.origin) - .namedPartsWith(ref => params.contains(ref.symbol)) + .namedPartsWith(ref => paramss.exists(_.contains(ref.symbol))) .nonEmpty => tvars + tp case _ => diff --git a/compiler/src/dotty/tools/dotc/typer/Inliner.scala b/compiler/src/dotty/tools/dotc/typer/Inliner.scala index c6c42ebe1b9f..db6165ed5f2f 100644 --- a/compiler/src/dotty/tools/dotc/typer/Inliner.scala +++ b/compiler/src/dotty/tools/dotc/typer/Inliner.scala @@ -200,10 +200,9 @@ object Inliner { flags = meth.flags &~ (Inline | Macro | Override) | Private, coord = mdef.rhs.span.startPos).asTerm retainer.deriveTargetNameAnnotation(meth, name => BodyRetainerName(name.asTermName)) - polyDefDef(retainer, targs => prefss => + DefDef(retainer, prefss => inlineCall( - ref(meth).appliedToTypes(targs).appliedToArgss(prefss) - .withSpan(mdef.rhs.span.startPos))( + ref(meth).appliedToArgss(prefss).withSpan(mdef.rhs.span.startPos))( using ctx.withOwner(retainer))) .showing(i"retainer for $meth: $result", inlining) @@ -365,7 +364,9 @@ class Inliner(call: tpd.Tree, rhsToInline: tpd.Tree)(using Context) { import tpd._ import Inliner._ - private val (methPart, callTypeArgs, callValueArgss) = decomposeCall(call) + private val methPart = funPart(call) + private val callTypeArgs = typeArgss(call).flatten + private val callValueArgss = termArgss(call) private val inlinedMethod = methPart.symbol private val inlineCallPrefix = qualifier(methPart).orElse(This(inlinedMethod.enclosingClass.asClass)) @@ -457,7 +458,7 @@ class Inliner(call: tpd.Tree, rhsToInline: tpd.Tree)(using Context) { paramSpan(name) = arg.span paramBinding(name) = arg.tpe.stripTypeVar } - computeParamBindings(tp.resultType, Nil, argss) + computeParamBindings(tp.resultType, targs.drop(tp.paramNames.length), argss) case tp: MethodType => if argss.isEmpty then report.error(i"missing arguments for inline method $inlinedMethod", call.srcPos) @@ -523,7 +524,7 @@ class Inliner(call: tpd.Tree, rhsToInline: tpd.Tree)(using Context) { case EmptyTree | TypeDef(_, _) | Import(_, _) - | DefDef(_, _, _, _, _) => + | DefDef(_, _, _, _) => true case vdef @ ValDef(_, _, _) => if (vdef.symbol.flags is Mutable) false else apply(vdef.rhs) @@ -961,7 +962,7 @@ class Inliner(call: tpd.Tree, rhsToInline: tpd.Tree)(using Context) { def betaReduce(tree: Tree)(using Context): Tree = tree match { case Apply(Select(cl @ closureDef(ddef), nme.apply), args) if defn.isFunctionType(cl.tpe) => ddef.tpe.widen match { - case mt: MethodType if ddef.vparamss.head.length == args.length => + case mt: MethodType if ddef.paramss.head.length == args.length => val bindingsBuf = new mutable.ListBuffer[ValOrDefDef] val argSyms = mt.paramNames.lazyZip(mt.paramInfos).lazyZip(args).map { (name, paramtp, arg) => arg.tpe.dealias match { @@ -975,7 +976,7 @@ class Inliner(call: tpd.Tree, rhsToInline: tpd.Tree)(using Context) { val expander = new TreeTypeMap( oldOwners = ddef.symbol :: Nil, newOwners = ctx.owner :: Nil, - substFrom = ddef.vparamss.head.map(_.symbol), + substFrom = ddef.paramss.head.map(_.symbol), substTo = argSyms) Block(bindingsBuf.toList, expander.transform(ddef.rhs)) case _ => tree @@ -1367,7 +1368,7 @@ class Inliner(call: tpd.Tree, rhsToInline: tpd.Tree)(using Context) { val bindingOfSym = MutableSymbolMap[MemberDef]() def isInlineable(binding: MemberDef) = binding match { - case ddef @ DefDef(_, Nil, Nil, _, _) => isElideableExpr(ddef.rhs) + case ddef @ DefDef(_, Nil, _, _) => isElideableExpr(ddef.rhs) case vdef @ ValDef(_, _, _) => isElideableExpr(vdef.rhs) case _ => false } diff --git a/compiler/src/dotty/tools/dotc/typer/Namer.scala b/compiler/src/dotty/tools/dotc/typer/Namer.scala index e31a2f1fdd12..45523f886b78 100644 --- a/compiler/src/dotty/tools/dotc/typer/Namer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Namer.scala @@ -696,7 +696,7 @@ class Namer { typer: Typer => protected def typeSig(sym: Symbol): Type = original match { case original: ValDef => if (sym.is(Module)) moduleValSig(sym) - else valOrDefDefSig(original, sym, Nil, Nil, identity)(using localContext(sym).setNewScope) + else valOrDefDefSig(original, sym, Nil, identity)(using localContext(sym).setNewScope) case original: DefDef => val typer1 = ctx.typer.newLikeThis nestedTyper(sym) = typer1 @@ -997,21 +997,23 @@ class Namer { typer: Typer => * provided `mbr` is accessible and of the right implicit/non-implicit kind. */ def addForwarder(alias: TermName, mbr: SingleDenotation, span: Span): Unit = + def adaptForwarderParams(acc: List[List[tpd.Tree]], tp: Type, prefss: List[List[tpd.Tree]]) : List[List[tpd.Tree]] = tp match - case mt: MethodType => + case mt: MethodType + if mt.paramInfos.nonEmpty && mt.paramInfos.last.isRepeatedParam => // Note: in this branch we use the assumptions // that `prefss.head` corresponds to `mt.paramInfos` and // that `prefss.tail` corresponds to `mt.resType` - if mt.paramInfos.nonEmpty && mt.paramInfos.last.isRepeatedParam then - val init :+ vararg = prefss.head - val prefs = init :+ ctx.typeAssigner.seqToRepeated(vararg) - adaptForwarderParams(prefs :: acc, mt.resType, prefss.tail) - else - adaptForwarderParams(prefss.head :: acc, mt.resType, prefss.tail) + val init :+ vararg = prefss.head + val prefs = init :+ ctx.typeAssigner.seqToRepeated(vararg) + adaptForwarderParams(prefs :: acc, mt.resType, prefss.tail) + case mt: MethodOrPoly => + adaptForwarderParams(prefss.head :: acc, mt.resultType, prefss.tail) case _ => acc.reverse ::: prefss - if (whyNoForwarder(mbr) == "") { + + if whyNoForwarder(mbr) == "" then val sym = mbr.symbol val forwarder = if mbr.isType then @@ -1046,9 +1048,8 @@ class Namer { typer: Typer => else { import tpd._ val ref = path.select(sym.asTerm) - val ddef = tpd.polyDefDef(forwarder.asTerm, targs => prefss => - ref.appliedToTypes(targs) - .appliedToArgss(adaptForwarderParams(Nil, sym.info.stripPoly, prefss)) + val ddef = tpd.DefDef(forwarder.asTerm, prefss => + ref.appliedToArgss(adaptForwarderParams(Nil, sym.info, prefss)) ) if forwarder.isInlineMethod then PrepareInlineable.registerInlineInfo(forwarder, ddef.rhs) @@ -1056,7 +1057,7 @@ class Namer { typer: Typer => } buf += forwarderDef.withSpan(span) - } + end addForwarder def addForwardersNamed(name: TermName, alias: TermName, span: Span): Unit = { val size = buf.size @@ -1315,7 +1316,7 @@ class Namer { typer: Typer => * @param paramFn A wrapping function that produces the type of the * defined symbol, given its final return type */ - def valOrDefDefSig(mdef: ValOrDefDef, sym: Symbol, typeParams: List[Symbol], paramss: List[List[Symbol]], paramFn: Type => Type)(using Context): Type = { + def valOrDefDefSig(mdef: ValOrDefDef, sym: Symbol, paramss: List[List[Symbol]], paramFn: Type => Type)(using Context): Type = { def inferredType = { /** A type for this definition that might be inherited from elsewhere: @@ -1326,35 +1327,37 @@ class Namer { typer: Typer => */ val inherited = if (sym.owner.isTerm) NoType - else { + else // TODO: Look only at member of supertype instead? lazy val schema = paramFn(WildcardType) val site = sym.owner.thisType + sym.owner.info.baseClasses.tail.foldLeft(NoType: Type) { (tp, cls) => - def instantiatedResType(info: Type, tparams: List[Symbol], paramss: List[List[Symbol]]): Type = info match { + def instantiatedResType(info: Type, paramss: List[List[Symbol]]): Type = info match case info: PolyType => - if (info.paramNames.length == typeParams.length) - instantiatedResType(info.instantiate(tparams.map(_.typeRef)), Nil, paramss) - else NoType + paramss match + case TypeSymbols(tparams) :: paramss1 if info.paramNames.length == tparams.length => + instantiatedResType(info.instantiate(tparams.map(_.typeRef)), paramss1) + case _ => + NoType case info: MethodType => - paramss match { - case params :: paramss1 if info.paramNames.length == params.length => - instantiatedResType(info.instantiate(params.map(_.termRef)), tparams, paramss1) + paramss match + case TermSymbols(vparams) :: paramss1 if info.paramNames.length == vparams.length => + instantiatedResType(info.instantiate(vparams.map(_.termRef)), paramss1) case _ => NoType - } case _ => - if (tparams.isEmpty && paramss.isEmpty) info.widenExpr + if paramss.isEmpty then info.widenExpr else NoType - } + val iRawInfo = cls.info.nonPrivateDecl(sym.name).matchingDenotation(site, schema, sym.targetName).info - val iResType = instantiatedResType(iRawInfo, typeParams, paramss).asSeenFrom(site, cls) + val iResType = instantiatedResType(iRawInfo, paramss).asSeenFrom(site, cls) if (iResType.exists) typr.println(i"using inherited type for ${mdef.name}; raw: $iRawInfo, inherited: $iResType") tp & iResType } - } + end inherited /** The proto-type to be used when inferring the result type from * the right hand side. This is `WildcardType` except if the definition @@ -1405,6 +1408,7 @@ class Namer { typer: Typer => var rhsCtx = ctx.fresh.addMode(Mode.InferringReturnType) if sym.isInlineMethod then rhsCtx = rhsCtx.addMode(Mode.InlineableBody) if sym.is(ExtensionMethod) then rhsCtx = rhsCtx.addMode(Mode.InExtensionMethod) + val typeParams = paramss.collect { case TypeSymbols(tparams) => tparams }.flatten if (typeParams.nonEmpty) { // we'll be typing an expression from a polymorphic definition's body, // so we must allow constraining its type parameters @@ -1439,6 +1443,7 @@ class Namer { typer: Typer => lhsType orElse WildcardType } } + lazy val termParamss = paramss.collect { case TermSymbols(vparams) => vparams } val tptProto = mdef.tpt match { case _: untpd.DerivedTypeTree => @@ -1446,7 +1451,7 @@ class Namer { typer: Typer => case TypeTree() => checkMembersOK(inferredType, mdef.srcPos) case DependentTypeTree(tpFun) => - val tpe = tpFun(paramss.head) + val tpe = tpFun(termParamss.head) if (isFullyDefined(tpe, ForceDegree.none)) tpe else typedAheadExpr(mdef.rhs, tpe).tpe case TypedSplice(tpt: TypeTree) if !isFullyDefined(tpt.tpe, ForceDegree.none) => @@ -1465,11 +1470,11 @@ class Namer { typer: Typer => // are better ways to achieve this. It would be good if we could get rid of this code. // It seems at least partially redundant with the nesting level checking on TypeVar // instantiation. - val hygienicType = TypeOps.avoid(rhsType, paramss.flatten) + val hygienicType = TypeOps.avoid(rhsType, termParamss.flatten) if (!hygienicType.isValueType || !(hygienicType <:< tpt.tpe)) report.error(i"return type ${tpt.tpe} of lambda cannot be made hygienic;\n" + i"it is not a supertype of the hygienic type $hygienicType", mdef.srcPos) - //println(i"lifting $rhsType over $paramss -> $hygienicType = ${tpt.tpe}") + //println(i"lifting $rhsType over $termParamss -> $hygienicType = ${tpt.tpe}") //println(TypeComparer.explained { implicit ctx => hygienicType <:< tpt.tpe }) case _ => } @@ -1486,7 +1491,6 @@ class Namer { typer: Typer => /** The type signature of a DefDef with given symbol */ def defDefSig(ddef: DefDef, sym: Symbol)(using Context): Type = { // Beware: ddef.name need not match sym.name if sym was freshened! - val DefDef(_, tparams, vparamss, _, _) = ddef val isConstructor = sym.name == nme.CONSTRUCTOR // The following 3 lines replace what was previously just completeParams(tparams). @@ -1512,23 +1516,22 @@ class Namer { typer: Typer => // 3. Info of CP is computed (to be copied to DP). // 4. CP is completed. // 5. Info of CP is copied to DP and DP is completed. - index(tparams) + index(ddef.leadingTypeParams) if (isConstructor) sym.owner.typeParams.foreach(_.ensureCompleted()) - for (tparam <- tparams) typedAheadExpr(tparam) + for (tparam <- ddef.leadingTypeParams) typedAheadExpr(tparam) - vparamss foreach completeParams - def typeParams = tparams map symbolOfTree - val termParamss = normalizeIfConstructor(vparamss.nestedMap(symbolOfTree), isConstructor) - sym.setParamss(typeParams, termParamss) + ddef.trailingParamss.foreach(completeParams) + val paramSymss = normalizeIfConstructor(ddef.paramss.nestedMap(symbolOfTree), isConstructor) + sym.setParamss(paramSymss) def wrapMethType(restpe: Type): Type = { - instantiateDependent(restpe, typeParams, termParamss) - methodType(tparams map symbolOfTree, termParamss, restpe, isJava = ddef.mods.is(JavaDefined)) + instantiateDependent(restpe, paramSymss) + methodType(paramSymss, restpe, isJava = ddef.mods.is(JavaDefined)) } if (isConstructor) { // set result type tree to unit, but take the current class as result type of the symbol typedAheadType(ddef.tpt, defn.UnitType) - wrapMethType(effectiveResultType(sym, typeParams, NoType)) + wrapMethType(effectiveResultType(sym, paramSymss, NoType)) } - else valOrDefDefSig(ddef, sym, typeParams, termParamss, wrapMethType) + else valOrDefDefSig(ddef, sym, paramSymss, wrapMethType) } } diff --git a/compiler/src/dotty/tools/dotc/typer/PrepareInlineable.scala b/compiler/src/dotty/tools/dotc/typer/PrepareInlineable.scala index 80682af5affa..46bfbbdeeba6 100644 --- a/compiler/src/dotty/tools/dotc/typer/PrepareInlineable.scala +++ b/compiler/src/dotty/tools/dotc/typer/PrepareInlineable.scala @@ -122,9 +122,10 @@ object PrepareInlineable { def preTransform(tree: Tree)(using Context): Tree = tree match { case _: Apply | _: TypeApply | _: RefTree if needsAccessor(tree.symbol) && tree.isTerm && !tree.symbol.isConstructor => - val (refPart, targs, argss) = decomposeCall(tree) + val refPart = funPart(tree) + val argss = allArgss(tree) val qual = qualifier(refPart) - inlining.println(i"adding receiver passing inline accessor for $tree/$refPart -> (${qual.tpe}, $refPart: ${refPart.getClass}, [$targs%, %], ($argss%, %))") + inlining.println(i"adding receiver passing inline accessor for $tree/$refPart -> (${qual.tpe}, $refPart: ${refPart.getClass}, $argss%, %") // Need to dealias in order to cagtch all possible references to abstracted over types in // substitutions @@ -159,10 +160,12 @@ object PrepareInlineable { accessorInfo = abstractQualType(addQualType(dealiasMap(accessedType))), accessed = accessed) - ref(accessor) - .appliedToTypeTrees(localRefs.map(TypeTree(_)) ++ targs) - .appliedToArgss((qual :: Nil) :: argss) - .withSpan(tree.span) + val (leadingTypeArgs, otherArgss) = splitArgs(argss) + val argss1 = joinArgs( + localRefs.map(TypeTree(_)) ++ leadingTypeArgs, // TODO: pass type parameters in two sections? + (qual :: Nil) :: otherArgss + ) + ref(accessor).appliedToArgss(argss1).withSpan(tree.span) // TODO: Handle references to non-public types. // This is quite tricky, as such types can appear anywhere, including as parts @@ -265,7 +268,7 @@ object PrepareInlineable { case Block(List(stat), Literal(Constants.Constant(()))) => checkMacro(stat) case Block(Nil, expr) => checkMacro(expr) case Typed(expr, _) => checkMacro(expr) - case Block(DefDef(nme.ANON_FUN, _, _, _, _) :: Nil, Closure(_, fn, _)) if fn.symbol.info.isImplicitMethod => + case Block(DefDef(nme.ANON_FUN, _, _, _) :: Nil, Closure(_, fn, _)) if fn.symbol.info.isImplicitMethod => // TODO Support this pattern report.error( """Macros using a return type of the form `foo(): X ?=> Y` are not yet supported. diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala index 75004a90b7e5..91ebd333c051 100644 --- a/compiler/src/dotty/tools/dotc/typer/Typer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala @@ -30,7 +30,7 @@ import TypeComparer.CompareResult import util.Spans._ import util.common._ import util.{Property, SimpleIdentityMap, SrcPos} -import Applications.{ExtMethodApply, IntegratedTypeArgs, productSelectorTypes, wrapDefs} +import Applications.{ExtMethodApply, productSelectorTypes, wrapDefs} import collection.mutable import annotation.tailrec @@ -548,11 +548,8 @@ class Typer extends Namer report.error(StableIdentPattern(tree, pt), tree.srcPos) def typedSelect(tree: untpd.Select, pt: Type, qual: Tree)(using Context): Tree = qual match { - case qual @ IntegratedTypeArgs(app) => - pt.revealIgnored match { - case _: PolyProto => qual // keep the IntegratedTypeArgs to strip at next typedTypeApply - case _ => app - } + case qual: ExtMethodApply => + qual.app case qual => val select = assignType(cpy.Select(tree)(qual, tree.name), qual) val select1 = toNotNullTermRef(select, pt) @@ -1088,14 +1085,14 @@ class Typer extends Namer if funFlags.is(Given) then params.map(_.withAddedFlags(Given)) else params val params2 = params1.map(fixThis.transformSub) - val appDef0 = untpd.DefDef(nme.apply, Nil, List(params2), body, EmptyTree).withSpan(tree.span) + val appDef0 = untpd.DefDef(nme.apply, List(params2), body, EmptyTree).withSpan(tree.span) index(appDef0 :: Nil) val appDef = typed(appDef0).asInstanceOf[DefDef] val mt = appDef.symbol.info.asInstanceOf[MethodType] if (mt.isParamDependent) report.error(i"$mt is an illegal function type because it has inter-parameter dependencies", tree.srcPos) val resTpt = TypeTree(mt.nonDependentResultApprox).withSpan(body.span) - val typeArgs = appDef.vparamss.head.map(_.tpt) :+ resTpt + val typeArgs = appDef.termParamss.head.map(_.tpt) :+ resTpt val tycon = TypeTree(funCls.typeRef) val core = AppliedTypeTree(tycon, typeArgs) RefinedTypeTree(core, List(appDef), ctx.owner.asClass) @@ -2000,34 +1997,36 @@ class Typer extends Namer sym.owner.info.decls.openForMutations.unlink(sym) return EmptyTree } - val DefDef(name, tparams, vparamss, tpt, _) = ddef + val DefDef(name, paramss, tpt, _) = ddef completeAnnotations(ddef, sym) - val tparams1 = tparams.mapconserve(typed(_).asInstanceOf[TypeDef]) - val vparamss1 = vparamss.nestedMapConserve(typed(_).asInstanceOf[ValDef]) - vparamss1.foreach(checkNoForwardDependencies) + val paramss1 = paramss.nestedMapConserve(typed(_)).asInstanceOf[List[ParamClause]] + for case ValDefs(vparams) <- paramss1 do + checkNoForwardDependencies(vparams) if (sym.isOneOf(GivenOrImplicit)) checkImplicitConversionDefOK(sym) val tpt1 = checkSimpleKinded(typedType(tpt)) val rhsCtx = ctx.fresh - if (tparams1.nonEmpty) { + val tparamss = paramss1.collect { + case untpd.TypeDefs(tparams) => tparams + } + if tparamss.nonEmpty then rhsCtx.setFreshGADTBounds - if (!sym.isConstructor) + val tparamSyms = tparamss.flatten.map(_.symbol) + if !sym.isConstructor then // we're typing a polymorphic definition's body, // so we allow constraining all of its type parameters // constructors are an exception as we don't allow constraining type params of classes - rhsCtx.gadt.addToConstraint(tparams1.map(_.symbol)) - else if (!sym.isPrimaryConstructor) { + rhsCtx.gadt.addToConstraint(tparamSyms) + else if !sym.isPrimaryConstructor then // otherwise, for secondary constructors we need a context that "knows" // that their type parameters are aliases of the class type parameters. // See pos/i941.scala - rhsCtx.gadt.addToConstraint(tparams1.map(_.symbol)) - tparams1.lazyZip(sym.owner.typeParams).foreach { (tdef, tparam) => + rhsCtx.gadt.addToConstraint(tparamSyms) + tparamSyms.lazyZip(sym.owner.typeParams).foreach { (psym, tparam) => val tr = tparam.typeRef - rhsCtx.gadt.addBound(tdef.symbol, tr, isUpper = false) - rhsCtx.gadt.addBound(tdef.symbol, tr, isUpper = true) + rhsCtx.gadt.addBound(psym, tr, isUpper = false) + rhsCtx.gadt.addBound(psym, tr, isUpper = true) } - } - } if sym.isInlineMethod then rhsCtx.addMode(Mode.InlineableBody) if sym.is(ExtensionMethod) then rhsCtx.addMode(Mode.InExtensionMethod) @@ -2045,7 +2044,7 @@ class Typer extends Namer if (sym.targetName != sym.name) report.error(em"@targetName annotation may not be used on a constructor", ddef.srcPos) - for (param <- tparams1 ::: vparamss1.flatten) + for params <- paramss1; param <- params do checkRefsLegal(param, sym.owner, (name, sym) => sym.is(TypeParam), "secondary constructor") def checkThisConstrCall(tree: Tree): Unit = tree match { @@ -2065,7 +2064,7 @@ class Typer extends Namer annot.tree.sourcePos ) - val ddef2 = assignType(cpy.DefDef(ddef)(name, tparams1, vparamss1, tpt1, rhs1), sym) + val ddef2 = assignType(cpy.DefDef(ddef)(name, paramss1, tpt1, rhs1), sym) checkSignatureRepeatedParam(sym) ddef2.setDefTree @@ -2385,7 +2384,7 @@ class Typer extends Namer nestedCtx.typerState.commit() if sourceVersion.isAtLeast(`3.1`) then lazy val (prefix, suffix) = res match { - case Block(mdef @ DefDef(_, _, vparams :: Nil, _, _) :: Nil, _: Closure) => + case Block(mdef @ DefDef(_, vparams :: Nil, _, _) :: Nil, _: Closure) => val arity = vparams.length if (arity > 0) ("", "") else ("(() => ", "())") case _ => @@ -2602,18 +2601,16 @@ class Typer extends Namer } /** Interpolate and simplify the type of the given tree. */ - protected def simplify(tree: Tree, pt: Type, locked: TypeVars)(using Context): tree.type = { - if (!tree.denot.isOverloaded && - // for overloaded trees: resolve overloading before simplifying - !tree.isInstanceOf[Applications.IntegratedTypeArgs]) - // don't interpolate in the middle of an extension method application - if (!tree.tpe.widen.isInstanceOf[MethodOrPoly] // wait with simplifying until method is fully applied - || tree.isDef) { // ... unless tree is a definition + protected def simplify(tree: Tree, pt: Type, locked: TypeVars)(using Context): tree.type = + if !tree.denot.isOverloaded // for overloaded trees: resolve overloading before simplifying + && !tree.isInstanceOf[Applications.AppProxy] // don't interpolate in the middle of an extension method application + then + if !tree.tpe.widen.isInstanceOf[MethodOrPoly] // wait with simplifying until method is fully applied + || tree.isDef // ... unless tree is a definition + then interpolateTypeVars(tree, pt, locked) tree.overwriteType(tree.tpe.simplified) - } tree - } protected def makeContextualFunction(tree: untpd.Tree, pt: Type)(using Context): Tree = { val defn.FunctionOf(formals, _, true, _) = pt.dropDependentRefinement @@ -3636,10 +3633,7 @@ class Typer extends Namer if tree.symbol.isAllOf(ApplyProxyFlags) then newExpr else adaptToArgs(wtp, pt) case pt: PolyProto => - tree match { - case _: IntegratedTypeArgs => tree - case _ => tryInsertApplyOrImplicit(tree, pt, locked)(tree) // error will be reported in typedTypeApply - } + tryInsertApplyOrImplicit(tree, pt, locked)(tree) // error will be reported in typedTypeApply case pt: SelectionProto if tree.isInstanceOf[ExtMethodApply] => tree case _ => diff --git a/compiler/src/dotty/tools/dotc/typer/VarianceChecker.scala b/compiler/src/dotty/tools/dotc/typer/VarianceChecker.scala index 9170c8edf8ad..5ece0b3d8128 100644 --- a/compiler/src/dotty/tools/dotc/typer/VarianceChecker.scala +++ b/compiler/src/dotty/tools/dotc/typer/VarianceChecker.scala @@ -208,10 +208,9 @@ class VarianceChecker(using Context) { } case tree: ValDef => checkVariance(sym, tree.srcPos) - case DefDef(_, tparams, vparamss, _, _) => + case DefDef(_, paramss, _, _) => checkVariance(sym, tree.srcPos) - tparams foreach traverse - vparamss foreach (_ foreach traverse) + paramss.foreach(_.foreach(traverse)) case _ => } catch { diff --git a/compiler/src/dotty/tools/repl/ReplCompiler.scala b/compiler/src/dotty/tools/repl/ReplCompiler.scala index 3580336830be..db9a2a7da2a4 100644 --- a/compiler/src/dotty/tools/repl/ReplCompiler.scala +++ b/compiler/src/dotty/tools/repl/ReplCompiler.scala @@ -280,7 +280,7 @@ class ReplCompiler extends Compiler { if (errorsAllowed || !ctx.reporter.hasErrors) unwrapped(unit.tpdTree, src) else - ctx.reporter.removeBufferedMessages.errors[tpd.ValDef] // Workaround #4988 + ctx.reporter.removeBufferedMessages.errors // Workaround #4988 } } } diff --git a/compiler/test/dotty/tools/dotc/BootstrappedOnlyCompilationTests.scala b/compiler/test/dotty/tools/dotc/BootstrappedOnlyCompilationTests.scala index 633f2d6758d2..64a76702c1ef 100644 --- a/compiler/test/dotty/tools/dotc/BootstrappedOnlyCompilationTests.scala +++ b/compiler/test/dotty/tools/dotc/BootstrappedOnlyCompilationTests.scala @@ -30,7 +30,8 @@ class BootstrappedOnlyCompilationTests extends ParallelTesting { // Positive tests ------------------------------------------------------------ - @Test def posMacros: Unit = { + @Test + def posMacros: Unit = { implicit val testGroup: TestGroup = TestGroup("compilePosMacros") aggregateTests( compileFilesInDir("tests/bench", defaultOptions), @@ -102,7 +103,8 @@ class BootstrappedOnlyCompilationTests extends ParallelTesting { // Negative tests ------------------------------------------------------------ - @Test def negMacros: Unit = { + @Test + def negMacros: Unit = { implicit val testGroup: TestGroup = TestGroup("compileNegWithCompiler") aggregateTests( compileFilesInDir("tests/neg-macros", defaultOptions), @@ -120,7 +122,8 @@ class BootstrappedOnlyCompilationTests extends ParallelTesting { // Run tests ----------------------------------------------------------------- - @Test def runMacros: Unit = { + @Test + def runMacros: Unit = { implicit val testGroup: TestGroup = TestGroup("runMacros") aggregateTests( compileFilesInDir("tests/run-macros", defaultOptions), diff --git a/compiler/test/dotty/tools/dotc/CompilationTests.scala b/compiler/test/dotty/tools/dotc/CompilationTests.scala index 742469bdcf22..749c3b02114c 100644 --- a/compiler/test/dotty/tools/dotc/CompilationTests.scala +++ b/compiler/test/dotty/tools/dotc/CompilationTests.scala @@ -157,7 +157,6 @@ class CompilationTests { compileFile("tests/neg-custom-args/missing-alpha.scala", defaultOptions.and("-Yrequire-targetName", "-Xfatal-warnings")), compileFile("tests/neg-custom-args/wildcards.scala", defaultOptions.and("-source", "3.1", "-deprecation", "-Xfatal-warnings")), compileFile("tests/neg-custom-args/indentRight.scala", defaultOptions.and("-noindent", "-Xfatal-warnings")), - compileFile("tests/neg-custom-args/extmethods-tparams.scala", defaultOptions.and("-deprecation", "-Xfatal-warnings")), compileDir("tests/neg-custom-args/adhoc-extension", defaultOptions.and("-source", "3.1", "-feature", "-Xfatal-warnings")), compileFile("tests/neg/i7575.scala", defaultOptions.withoutLanguageFeatures.and("-language:_")), compileFile("tests/neg-custom-args/kind-projector.scala", defaultOptions.and("-Ykind-projector")), @@ -250,7 +249,7 @@ class CompilationTests { val tastyCoreSources = sources(Paths.get("tasty/src")) val tastyCore = compileList("tastyCore", tastyCoreSources, opt)(tastyCoreGroup) - val compilerSources = sources(Paths.get("compiler/src")) + val compilerSources = sources(Paths.get("compiler/src")) ++ sources(Paths.get("compiler/src-bootstrapped")) val compilerManagedSources = sources(Properties.dottyCompilerManagedSources) val dotty1 = compileList("dotty1", compilerSources ++ compilerManagedSources, opt)(dotty1Group) diff --git a/compiler/test/dotty/tools/dotc/parsing/DeSugarTest.scala b/compiler/test/dotty/tools/dotc/parsing/DeSugarTest.scala index b19c35244854..51327e99dd01 100644 --- a/compiler/test/dotty/tools/dotc/parsing/DeSugarTest.scala +++ b/compiler/test/dotty/tools/dotc/parsing/DeSugarTest.scala @@ -59,8 +59,8 @@ class DeSugarTest extends ParserTest { cpy.UnApply(tree1)(transform(fun, Expr), transform(implicits), transform(patterns)) case tree1 @ ValDef(name, tpt, _) => cpy.ValDef(tree1)(name, transform(tpt, Type), transform(tree1.rhs)) - case tree1 @ DefDef(name, tparams, vparamss, tpt, _) => - cpy.DefDef(tree1)(name, transformSub(tparams), vparamss mapConserve (transformSub(_)), transform(tpt, Type), transform(tree1.rhs)) + case tree1 @ DefDef(name, paramss, tpt, _) => + cpy.DefDef(tree1)(name, transformParamss(paramss), transform(tpt, Type), transform(tree1.rhs)) case tree1 @ TypeDef(name, rhs) => cpy.TypeDef(tree1)(name, transform(rhs, Type)) case impl @ Template(constr, parents, self, _) => diff --git a/compiler/test/dotty/tools/dotc/parsing/ModifiersParsingTest.scala b/compiler/test/dotty/tools/dotc/parsing/ModifiersParsingTest.scala index 952e8dfbe27f..15d43653025a 100644 --- a/compiler/test/dotty/tools/dotc/parsing/ModifiersParsingTest.scala +++ b/compiler/test/dotty/tools/dotc/parsing/ModifiersParsingTest.scala @@ -24,22 +24,22 @@ object ModifiersParsingTest { extension (code: Tree) { def firstConstrValDef: ValDef = code match { case d.TypeDef(_, d.Template(constr, _, _, _)) => - constr.vparamss.head.head + constr.termParamss.head.head } def firstTypeParam: TypeDef = code match { case d.TypeDef(_, d.Template(constr, _, _, _)) => - constr.tparams.head + constr.leadingTypeParams.head } def defParam(i: Int): ValDef = code match { - case d.DefDef(_, _, vparamss, _, _) => - vparamss.head.toArray.apply(i) + case code @ d.DefDef(_, _, _, _) => + code.termParamss.head.toArray.apply(i) } def defParam(i: Int, j: Int): ValDef = code match { - case d.DefDef(_, _, vparamss, _, _) => - vparamss.toArray.apply(i).toArray.apply(j) + case code @ d.DefDef(_, _, _, _) => + code.termParamss.toArray.apply(i).toArray.apply(j) } def funParam(i: Int): Tree = code match { diff --git a/compiler/test/dotty/tools/dotc/printing/PrinterTests.scala b/compiler/test/dotty/tools/dotc/printing/PrinterTests.scala index acf7610238a2..8ce53e28b93d 100644 --- a/compiler/test/dotty/tools/dotc/printing/PrinterTests.scala +++ b/compiler/test/dotty/tools/dotc/printing/PrinterTests.scala @@ -46,7 +46,7 @@ class PrinterTests extends DottyTest { checkCompile("typer", source) { (tree, context) => given Context = context - val bar @ Trees.DefDef(_, _, _, _, _) = tree.find(tree => tree.symbol.name == termName("bar2")).get + val bar @ Trees.DefDef(_, _, _, _) = tree.find(tree => tree.symbol.name == termName("bar2")).get assertEquals("Int & (Boolean | String)", bar.tpt.show) } } diff --git a/doc-tool/src/dotty/tools/dottydoc/core/DocImplicitsPhase.scala b/doc-tool/src/dotty/tools/dottydoc/core/DocImplicitsPhase.scala index 479dce95c068..e9f61c47dce5 100644 --- a/doc-tool/src/dotty/tools/dottydoc/core/DocImplicitsPhase.scala +++ b/doc-tool/src/dotty/tools/dottydoc/core/DocImplicitsPhase.scala @@ -13,15 +13,13 @@ class DocImplicitsPhase extends MiniPhase { def phaseName = "addImplicitsPhase" override def transformDefDef(tree: DefDef)(using Context): Tree = { - if ( - tree.symbol.isOneOf(Flags.GivenOrImplicit) && // has to have an implicit flag - tree.symbol.owner.isStaticOwner && // owner has to be static (e.g. top-level `object`) - tree.vparamss.length > 0 && - tree.vparamss(0).length == 1 // should only take one arg, since it has to be a transformation - ) { - val convertee = tree.vparamss(0)(0).symbol.info.widenDealias.finalResultType.typeSymbol // the pimped type (i.e. `class`) + if tree.symbol.isOneOf(Flags.GivenOrImplicit) // has to have an implicit flag + && tree.symbol.owner.isStaticOwner // owner has to be static (e.g. top-level `object`) + && tree.termParamss.length > 0 + && tree.termParamss(0).length == 1 // should only take one arg, since it has to be a transformation + then + val convertee = tree.termParamss(0)(0).symbol.info.widenDealias.finalResultType.typeSymbol // the pimped type (i.e. `class`) ctx.docbase.addDef(convertee, tree.symbol.info.widenDealias.finalResultType.typeSymbol) - } tree } diff --git a/docs/docs/reference/contextual/extension-methods.md b/docs/docs/reference/contextual/extension-methods.md index 6a0a2eac0375..b650e2ea81cb 100644 --- a/docs/docs/reference/contextual/extension-methods.md +++ b/docs/docs/reference/contextual/extension-methods.md @@ -59,8 +59,8 @@ Note the swap of the two parameters `x` and `xs` when translating the right-associative operator `+:` to an extension method. This is analogous to the implementation of right binding operators as normal methods. The Scala compiler preprocesses an infix operation `x +: xs` to `xs.+:(x)`, so the extension -method ends up being applied to the sequence as first argument (in other words, -the two swaps cancel each other out). +method ends up being applied to the sequence as first argument (in other words, the +two swaps cancel each other out). See [here for details](./right-associative-extension-methods.html). ### Generic Extensions @@ -74,27 +74,32 @@ extension [T: Numeric](x: T) def + (y: T): T = summon[Numeric[T]].plus(x, y) ``` -If an extension method has type parameters, they come immediately after `extension` and are followed by the extended parameter. -When calling a generic extension method, any explicitly given type arguments follow the method name. -So the `second` method could be instantiated as follows: - +Type parameters on extensions can also be combined with type parameters on the methods +themselves: ```scala -List(1, 2, 3).second[Int] +extension [T](xs: List[T]) + def def sumBy[B](f: A => B)(using Numeric[B]): B = ... ``` -Of course, the type argument here would usually be left out since it can be inferred. - +Type arguments matching method type parameters are passed as usual: +```scala +List("a", "bb", "ccc").sumBy[Int](_.length) +``` +By contrast, type arguments matching type parameters following `extension` can be passed +only if the method is referenced as a regular method: +```scala +List[String]("a", "bb", "ccc").sumBy(_.length) +``` +or, passing, both type arguments +```scala +List[String]("a", "bb", "ccc").sumBy[Int](_.length) +``` Extensions can also take using clauses. For instance, the `+` extension above could equivalently be written with a using clause: ```scala extension [T](x: T)(using n: Numeric[T]) def + (y: T): T = n.plus(x, y) ``` - -**Note**: Type parameters have to be given after the `extension` keyword; they cannot be given after the `def`. -This restriction might be lifted in the future once we support multiple type parameter clauses in a method. -By contrast, using clauses can be defined for the `extension` as well as per `def`. - ### Collective Extensions Sometimes, one wants to define several extension methods that share the same diff --git a/docs/docs/reference/contextual/right-associative-extension-methods.md b/docs/docs/reference/contextual/right-associative-extension-methods.md new file mode 100644 index 000000000000..aa866a854926 --- /dev/null +++ b/docs/docs/reference/contextual/right-associative-extension-methods.md @@ -0,0 +1,45 @@ +--- +layout: doc-page +title: "Right-Associative Extension Methods: Details" +--- + +The most general form of leading parameters of an extension method is as follows: + + - A possibly empty list of using clauses `leadingUsing` + - A single parameter `extensionParam` + - A possibly empty list of using clauses `trailingUsing` + +This is then followed by `def`, the method name, and possibly further parameters +`otherParams`. An example is: + +```scala + extension (using a: A, b: B)(using c: C) // <-- leadingUsing + (x: X) // <-- extensionParam + (using d: D) // <-- trailingUsing + def +:: (y: Y)(using e: E)(z: Z) // <-- otherParams +``` +An extension method is treated as a right associative operator if +it has a name ending in `:` and is immediately followed by a +single parameter. In the example above, that parameter is `(y: Y)`. + +The Scala compiler pre-processes a right-associative infix operation such as `x +: xs` +to `xs.+:(x)` if `x` and `xs` are pure expressions or `x` is a call-by-name parameter and to `val y = x; xs.+:(y)` otherwise. This is necessary since a regular right-associative infix method +is defined in the class of its right operand. To make up for this swap, +the expansion of right-associative extension methods performs an analogous parameter swap. More precisely, if `otherParams` consists of a single parameter +`rightParam` followed by `remaining`, the total parameter sequence +of the extension method's expansion is: +``` + leadingUsing rightParam trailingUsing extensionParam remaining +``` +For instance, the `+::` method above would become +```scala + def +:: (using a: A, b: B)(using c: C) + (y: Y) + (using d: D) + (x: X) + (using e: E)(z: Z) +``` +This expansion has to be kept in mind when writing right-associative extension +methods with inter-parameter dependencies. + +An overall simpler design could be obtained if right-associative operators could _only_ be defined as extension methods, and would be disallowed as normal methods. In that case neither arguments nor parameters would have to be swapped. Future versions of Scala should strive to achieve this simplification. diff --git a/docs/docs/reference/contextual/type-classes.md b/docs/docs/reference/contextual/type-classes.md index e771595a28e5..5911eff48eed 100644 --- a/docs/docs/reference/contextual/type-classes.md +++ b/docs/docs/reference/contextual/type-classes.md @@ -101,16 +101,16 @@ As in the previous example of Monoids, [`extension` methods](extension-methods.m ```scala trait Functor[F[_]]: - extension [A, B](x: F[A]) - def map(f: A => B): F[B] + extension [A](x: F[A]) + def map[B](f: A => B): F[B] ``` The instance of `Functor` for `List` now becomes: ```scala given Functor[List] with - extension [A, B](xs: List[A]) - def map(f: A => B): List[B] = + extension [A](xs: List[A]) + def map[B](f: A => B): List[B] = xs.map(f) // List already has a `map` method ``` @@ -143,12 +143,12 @@ trait Monad[F[_]] extends Functor[F]: /** The unit value for a monad */ def pure[A](x: A): F[A] - extension [A, B](x: F[A]) + extension [A](x: F[A]) /** The fundamental composition operation */ - def flatMap(f: A => F[B]): F[B] + def flatMap[B](f: A => F[B]): F[B] /** The `map` operation can now be defined in terms of `flatMap` */ - def map(f: A => B) = x.flatMap(f.andThen(pure)) + def map[B](f: A => B) = x.flatMap(f.andThen(pure)) end Monad ``` @@ -161,8 +161,8 @@ A `List` can be turned into a monad via this `given` instance: given listMonad: Monad[List] with def pure[A](x: A): List[A] = List(x) - extension [A, B](xs: List[A]) - def flatMap(f: A => List[B]): List[B] = + extension [A](xs: List[A]) + def flatMap[B](f: A => List[B]): List[B] = xs.flatMap(f) // rely on the existing `flatMap` method of `List` ``` @@ -178,8 +178,8 @@ it explicitly. given optionMonad: Monad[Option] with def pure[A](x: A): Option[A] = Option(x) - extension [A, B](xo: Option[A]) - def flatMap(f: A => Option[B]): Option[B] = xo match + extension [A](xo: Option[A]) + def flatMap[B](f: A => Option[B]): Option[B] = xo match case Some(x) => f(x) case None => None ``` @@ -227,8 +227,8 @@ given configDependentMonad: Monad[ConfigDependent] with def pure[A](x: A): ConfigDependent[A] = config => x - extension [A, B](x: ConfigDependent[A]) - def flatMap(f: A => ConfigDependent[B]): ConfigDependent[B] = + extension [A](x: ConfigDependent[A]) + def flatMap[B](f: A => ConfigDependent[B]): ConfigDependent[B] = config => f(x(config))(config) end configDependentMonad @@ -248,8 +248,8 @@ given configDependentMonad: Monad[[Result] =>> Config => Result] with def pure[A](x: A): Config => A = config => x - extension [A, B](x: Config => A) - def flatMap(f: A => Config => B): Config => B = + extension [A](x: Config => A) + def flatMap[B](f: A => Config => B): Config => B = config => f(x(config))(config) end configDependentMonad @@ -263,8 +263,8 @@ given readerMonad[Ctx]: Monad[[X] =>> Ctx => X] with def pure[A](x: A): Ctx => A = ctx => x - extension [A, B](x: Ctx => A) - def flatMap(f: A => Ctx => B): Ctx => B = + extension [A](x: Ctx => A) + def flatMap[B](f: A => Ctx => B): Ctx => B = ctx => f(x(ctx))(ctx) end readerMonad diff --git a/library/src-bootstrapped/scala/IArray.scala b/library/src-bootstrapped/scala/IArray.scala index 21a36e00b565..75fcb758a3dc 100644 --- a/library/src-bootstrapped/scala/IArray.scala +++ b/library/src-bootstrapped/scala/IArray.scala @@ -43,7 +43,7 @@ object opaques: extension [T](arr: IArray[T]) def length: Int = arr.asInstanceOf[Array[T]].length /** Returns this array concatenated with the given array. */ - extension [T, U >: T: ClassTag](arr: IArray[T]) def ++(that: IArray[U]): IArray[U] = + extension [T](arr: IArray[T]) def ++ [U >: T: ClassTag](that: IArray[U]): IArray[U] = genericArrayOps(arr) ++ that /** Tests whether this array contains a given value as an element. */ @@ -53,15 +53,15 @@ object opaques: genericArrayOps(arr).exists(_ == elem) /** Copy elements of this array to another array. */ - extension [T, U >: T](arr: IArray[T]) def copyToArray(xs: Array[U]): Int = + extension [T](arr: IArray[T]) def copyToArray[U >: T](xs: Array[U]): Int = genericArrayOps(arr).copyToArray(xs) /** Copy elements of this array to another array. */ - extension [T, U >: T](arr: IArray[T]) def copyToArray(xs: Array[U], start: Int): Int = + extension [T](arr: IArray[T]) def copyToArray[U >: T](xs: Array[U], start: Int): Int = genericArrayOps(arr).copyToArray(xs, start) /** Copy elements of this array to another array. */ - extension [T, U >: T](arr: IArray[T]) def copyToArray(xs: Array[U], start: Int, len: Int): Int = + extension [T](arr: IArray[T]) def copyToArray[U >: T](xs: Array[U], start: Int, len: Int): Int = genericArrayOps(arr).copyToArray(xs, start, len) /** Counts the number of elements in this array which satisfy a predicate */ @@ -98,26 +98,26 @@ object opaques: /** Builds a new array by applying a function to all elements of this array * and using the elements of the resulting collections. */ - extension [T, U: ClassTag](arr: IArray[T]) def flatMap(f: T => IterableOnce[U]): IArray[U] = + extension [T](arr: IArray[T]) def flatMap[U: ClassTag](f: T => IterableOnce[U]): IArray[U] = genericArrayOps(arr).flatMap(f) /** Flattens a two-dimensional array by concatenating all its rows * into a single array. */ - extension [T, U: ClassTag](arr: IArray[T]) def flatten(using T => Iterable[U]): IArray[U] = + extension [T](arr: IArray[T]) def flatten[U: ClassTag](using T => Iterable[U]): IArray[U] = genericArrayOps(arr).flatten /** Folds the elements of this array using the specified associative binary operator. */ - extension [T, U >: T: ClassTag](arr: IArray[T]) def fold(z: U)(op: (U, U) => U): U = + extension [T](arr: IArray[T]) def fold[U >: T: ClassTag](z: U)(op: (U, U) => U): U = genericArrayOps(arr).fold(z)(op) /** Applies a binary operator to a start value and all elements of this array, * going left to right. */ - extension [T, U: ClassTag](arr: IArray[T]) def foldLeft(z: U)(op: (U, T) => U): U = + extension [T](arr: IArray[T]) def foldLeft[U: ClassTag](z: U)(op: (U, T) => U): U = genericArrayOps(arr).foldLeft(z)(op) /** Applies a binary operator to all elements of this array and a start value, * going right to left. */ - extension [T, U: ClassTag](arr: IArray[T]) def foldRight(z: U)(op: (T, U) => U): U = + extension [T](arr: IArray[T]) def foldRight[U: ClassTag](z: U)(op: (T, U) => U): U = genericArrayOps(arr).foldRight(z)(op) /** Tests whether a predicate holds for all elements of this array. */ @@ -125,7 +125,7 @@ object opaques: genericArrayOps(arr).forall(p) /** Apply `f` to each element for its side effects. */ - extension [T, U](arr: IArray[T]) def foreach(f: T => U): Unit = + extension [T](arr: IArray[T]) def foreach[U](f: T => U): Unit = genericArrayOps(arr).foreach(f) /** Selects the first element of this array. */ @@ -181,7 +181,7 @@ object opaques: genericArrayOps(arr).lastIndexWhere(p, end) /** Builds a new array by applying a function to all elements of this array. */ - extension [T, U: ClassTag](arr: IArray[T]) def map(f: T => U): IArray[U] = + extension [T](arr: IArray[T]) def map[U: ClassTag](f: T => U): IArray[U] = genericArrayOps(arr).map(f) /** Tests whether the array is not empty. */ @@ -197,17 +197,17 @@ object opaques: genericArrayOps(arr).reverse /** Computes a prefix scan of the elements of the array. */ - extension [T, U >: T: ClassTag](arr: IArray[T]) def scan(z: U)(op: (U, U) => U): IArray[U] = + extension [T](arr: IArray[T]) def scan[U >: T: ClassTag](z: U)(op: (U, U) => U): IArray[U] = genericArrayOps(arr).scan(z)(op) /** Produces an array containing cumulative results of applying the binary * operator going left to right. */ - extension [T, U: ClassTag](arr: IArray[T]) def scanLeft(z: U)(op: (U, T) => U): IArray[U] = + extension [T](arr: IArray[T]) def scanLeft[U: ClassTag](z: U)(op: (U, T) => U): IArray[U] = genericArrayOps(arr).scanLeft(z)(op) /** Produces an array containing cumulative results of applying the binary * operator going right to left. */ - extension [T, U: ClassTag](arr: IArray[T]) def scanRight(z: U)(op: (T, U) => U): IArray[U] = + extension [T](arr: IArray[T]) def scanRight[U: ClassTag](z: U)(op: (T, U) => U): IArray[U] = genericArrayOps(arr).scanRight(z)(op) /** The size of this array. */ @@ -220,7 +220,7 @@ object opaques: /** Sorts this array according to the Ordering which results from transforming * an implicitly given Ordering with a transformation function. */ - extension [T, U: ClassTag](arr: IArray[T]) def sortBy(f: T => U)(using math.Ordering[U]): IArray[T] = + extension [T](arr: IArray[T]) def sortBy[U: ClassTag](f: T => U)(using math.Ordering[U]): IArray[T] = genericArrayOps(arr).sortBy(f) /** Sorts this array according to a comparison function. */ @@ -240,7 +240,7 @@ object opaques: genericArrayOps(arr).splitAt(n) /** Tests whether this array starts with the given array. */ - extension [T, U >: T: ClassTag](arr: IArray[T]) def startsWith(that: IArray[U], offset: Int = 0): Boolean = + extension [T](arr: IArray[T]) def startsWith[U >: T: ClassTag](that: IArray[U], offset: Int = 0): Boolean = genericArrayOps(arr).startsWith(that) /** The rest of the array without its first element. */ @@ -270,7 +270,7 @@ object opaques: /** Returns an array formed from this array and another iterable collection * by combining corresponding elements in pairs. * If one of the two collections is longer than the other, its remaining elements are ignored. */ - extension [T, U: ClassTag](arr: IArray[T]) def zip(that: IArray[U]): IArray[(T, U)] = + extension [T](arr: IArray[T]) def zip[U: ClassTag](that: IArray[U]): IArray[(T, U)] = genericArrayOps(arr).zip(that) } end opaques diff --git a/library/src-bootstrapped/scala/quoted/Quotes.scala b/library/src-bootstrapped/scala/quoted/Quotes.scala index f96f373ea6e8..1bdadd3e85af 100644 --- a/library/src-bootstrapped/scala/quoted/Quotes.scala +++ b/library/src-bootstrapped/scala/quoted/Quotes.scala @@ -53,12 +53,12 @@ trait Quotes { self: runtime.QuoteUnpickler & runtime.QuoteMatching => end extension // Extension methods for `Expr[Any]` that take another explicit type parameter - extension [X](self: Expr[Any]) + extension (self: Expr[Any]) /** Checks is the `quoted.Expr[?]` is valid expression of type `X` */ - def isExprOf(using Type[X]): Boolean + def isExprOf[X](using Type[X]): Boolean /** Convert this to an `quoted.Expr[X]` if this expression is a valid expression of type `X` or throws */ - def asExprOf(using Type[X]): Expr[X] + def asExprOf[X](using Type[X]): Expr[X] end extension /** Low-level Typed AST metaprogramming API. @@ -248,8 +248,8 @@ trait Quotes { self: runtime.QuoteUnpickler & runtime.QuoteMatching => end extension /** Convert this tree to an `quoted.Expr[T]` if the tree is a valid expression or throws */ - extension [T](self: Tree) - def asExprOf(using Type[T]): Expr[T] + extension (self: Tree) + def asExprOf[T](using Type[T]): Expr[T] extension [ThisTree <: Tree](self: ThisTree) /** Changes the owner of the symbols in the tree */ diff --git a/library/src/scala/quoted/ExprMap.scala b/library/src/scala/quoted/ExprMap.scala index c6163f14207b..dee994cdfdfb 100644 --- a/library/src/scala/quoted/ExprMap.scala +++ b/library/src/scala/quoted/ExprMap.scala @@ -145,7 +145,9 @@ trait ExprMap: trees.mapConserve(x => transformTypeCaseDef(x)(owner)) } - new MapChildren().transformTermChildren(e.asTerm, TypeRepr.of[T])(Symbol.spliceOwner).asExprOf[T] + new MapChildren() + .transformTermChildren(e.asTerm, TypeRepr.of[T])(Symbol.spliceOwner) + .asExprOf: Expr[T] } end ExprMap diff --git a/scala3doc-testcases/src/tests/extensionMethodSignatures.scala b/scala3doc-testcases/src/tests/extensionMethodSignatures.scala index 50152cc2ef1d..34237da32983 100644 --- a/scala3doc-testcases/src/tests/extensionMethodSignatures.scala +++ b/scala3doc-testcases/src/tests/extensionMethodSignatures.scala @@ -15,7 +15,7 @@ class ClassOne = 56 extension (c: ClassTwo) - def |||:(a: Int, b: Int, d: Int)(e: String): Int + def |||:(a: Int)(b: Int, d: Int)(e: String): Int = 56 def ++:(a: Int): Int = 45 diff --git a/tasty/src/dotty/tools/tasty/TastyFormat.scala b/tasty/src/dotty/tools/tasty/TastyFormat.scala index d9ec4fc49bc1..2315d67bc4de 100644 --- a/tasty/src/dotty/tools/tasty/TastyFormat.scala +++ b/tasty/src/dotty/tools/tasty/TastyFormat.scala @@ -62,17 +62,21 @@ Standard-Section: "ASTs" TopLevelStat* IMPORT Length qual_Term Selector* -- import qual selectors EXPORT Length qual_Term Selector* -- export qual selectors ValOrDefDef = VALDEF Length NameRef type_Term rhs_Term? Modifier* -- modifiers val name : type (= rhs)? - DEFDEF Length NameRef TypeParam* Params* returnType_Term - rhs_Term? Modifier* -- modifiers def name [typeparams] paramss : returnType (= rhs)? + DEFDEF Length NameRef Param* returnType_Term rhs_Term? + Modifier* -- modifiers def name [typeparams] paramss : returnType (= rhs)? Selector = IMPORTED name_NameRef -- name, "_" for normal wildcards, "" for given wildcards RENAMED to_NameRef -- => name BOUNDED type_Term -- type bound TypeParam = TYPEPARAM Length NameRef type_Term Modifier* -- modifiers name bounds - Param = PARAM Length NameRef type_Term rhs_Term? Modifier* -- modifiers name : type (= rhs_Term)?. `rhsTerm` is present in the case of an aliased class parameter - PARAMEND -- ends a parameter clause + TermParam = PARAM Length NameRef type_Term rhs_Term? Modifier* -- modifiers name : type (= rhs_Term)?. `rhsTerm` is present in the case of an aliased class parameter + EMPTYCLAUSE -- an empty parameter clause () + SPLITCLAUSE -- splits two non-empty parameter clauses of the same kind + Param = TypeParam + TermParam -- needed if previous parameter clause is empty or another parameter clause follows - Template = TEMPLATE Length TypeParam* Param* parent_Term* Self? Stat* -- [typeparams] paramss extends parents { self => stats }, where Stat* always starts with the primary constructor. + Template = TEMPLATE Length TypeParam* TermParam* parent_Term* Self? + Stat* -- [typeparams] paramss extends parents { self => stats }, where Stat* always starts with the primary constructor. Self = SELFDEF selfName_NameRef selfType_Term -- selfName : selfType Term = Path -- Paths represent both types and terms @@ -222,9 +226,9 @@ Note: The signature of a SELECTin or TERMREFin node is the signature of the sele Note: Tree tags are grouped into 5 categories that determine what follows, and thus allow to compute the size of the tagged tree in a generic way. - Category 1 (tags 1-49) : tag - Category 2 (tags 50-79) : tag Nat - Category 3 (tags 80-109) : tag AST + Category 1 (tags 1-59) : tag + Category 2 (tags 60-89) : tag Nat + Category 3 (tags 90-109) : tag AST Category 4 (tags 110-127): tag Nat AST Category 5 (tags 128-255): tag Length @@ -260,8 +264,8 @@ Standard Section: "Comments" Comment* object TastyFormat { final val header: Array[Int] = Array(0x5C, 0xA1, 0xAB, 0x1F) - val MajorVersion: Int = 26 - val MinorVersion: Int = 1 + val MajorVersion: Int = 27 + val MinorVersion: Int = 0 final val ASTsSection = "ASTs" final val PositionsSection = "Positions" @@ -374,46 +378,47 @@ object TastyFormat { final val PARAMsetter = 38 final val EXPORTED = 39 final val OPEN = 40 - final val PARAMEND = 41 - final val PARAMalias = 42 - final val TRANSPARENT = 43 - final val INFIX = 44 + final val PARAMalias = 41 + final val TRANSPARENT = 42 + final val INFIX = 43 + final val EMPTYCLAUSE = 44 + final val SPLITCLAUSE = 45 // Cat. 2: tag Nat - final val SHAREDterm = 50 - final val SHAREDtype = 51 - final val TERMREFdirect = 52 - final val TYPEREFdirect = 53 - final val TERMREFpkg = 54 - final val TYPEREFpkg = 55 - final val RECthis = 56 - final val BYTEconst = 57 - final val SHORTconst = 58 - final val CHARconst = 59 - final val INTconst = 60 - final val LONGconst = 61 - final val FLOATconst = 62 - final val DOUBLEconst = 63 - final val STRINGconst = 64 - final val IMPORTED = 65 - final val RENAMED = 66 + final val SHAREDterm = 60 + final val SHAREDtype = 61 + final val TERMREFdirect = 62 + final val TYPEREFdirect = 63 + final val TERMREFpkg = 64 + final val TYPEREFpkg = 65 + final val RECthis = 66 + final val BYTEconst = 67 + final val SHORTconst = 68 + final val CHARconst = 69 + final val INTconst = 70 + final val LONGconst = 71 + final val FLOATconst = 72 + final val DOUBLEconst = 73 + final val STRINGconst = 74 + final val IMPORTED = 75 + final val RENAMED = 76 // Cat. 3: tag AST - final val THIS = 80 - final val QUALTHIS = 81 - final val CLASSconst = 82 - final val BYNAMEtype = 83 - final val BYNAMEtpt = 84 - final val NEW = 85 - final val THROW = 86 - final val IMPLICITarg = 87 - final val PRIVATEqualified = 88 - final val PROTECTEDqualified = 89 - final val RECtype = 90 - final val SINGLETONtpt = 91 - final val BOUNDED = 92 + final val THIS = 90 + final val QUALTHIS = 91 + final val CLASSconst = 92 + final val BYNAMEtype = 93 + final val BYNAMEtpt = 94 + final val NEW = 95 + final val THROW = 96 + final val IMPLICITarg = 97 + final val PRIVATEqualified = 98 + final val PROTECTEDqualified = 99 + final val RECtype = 100 + final val SINGLETONtpt = 101 + final val BOUNDED = 102 // Cat. 4: tag Nat AST @@ -493,7 +498,7 @@ object TastyFormat { /** Useful for debugging */ def isLegalTag(tag: Int): Boolean = - firstSimpleTreeTag <= tag && tag <= INFIX || + firstSimpleTreeTag <= tag && tag <= SPLITCLAUSE || firstNatTreeTag <= tag && tag <= RENAMED || firstASTTreeTag <= tag && tag <= BOUNDED || firstNatASTTreeTag <= tag && tag <= NAMEDARG || @@ -602,8 +607,9 @@ object TastyFormat { case PARAMsetter => "PARAMsetter" case EXPORTED => "EXPORTED" case OPEN => "OPEN" - case PARAMEND => "PARAMEND" case PARAMalias => "PARAMalias" + case EMPTYCLAUSE => "EMPTYCLAUSE" + case SPLITCLAUSE => "SPLITCLAUSE" case SHAREDterm => "SHAREDterm" case SHAREDtype => "SHAREDtype" diff --git a/tests/neg-custom-args/extmethods-tparams.scala b/tests/neg-custom-args/extmethods-tparams.scala deleted file mode 100644 index 9cf6e94c14c4..000000000000 --- a/tests/neg-custom-args/extmethods-tparams.scala +++ /dev/null @@ -1,2 +0,0 @@ -extension (self: T) def foo[T] = ??? // error -extension [T1](self: T1) def bar[T2] = ??? // error \ No newline at end of file diff --git a/tests/neg/extension-cannot-have-type.scala b/tests/neg/extension-cannot-have-type.scala deleted file mode 100644 index c6fd2d3df4b4..000000000000 --- a/tests/neg/extension-cannot-have-type.scala +++ /dev/null @@ -1,5 +0,0 @@ -object Test { - extension [T] (t: T) { - def f[U](u: U): T = ??? // error: extension method cannot have type parameters here, all type parameters go after `extension` - } -} \ No newline at end of file diff --git a/tests/neg/i6900.scala b/tests/neg/i6900.scala deleted file mode 100644 index 18231f4e6cda..000000000000 --- a/tests/neg/i6900.scala +++ /dev/null @@ -1,15 +0,0 @@ -object Test2 { - - // Works with extension method - extension [A](a: A) - def foo[C]: C => A = _ => a // error: extension method cannot have type parameters - - 1.foo.foo - - // ... but have to pass 2 parameters - 1.foo.foo[Any => Int, String] - 1.foo[Int, String].foo - 1.foo[Int, String].foo[String => Int, String] - -} - diff --git a/tests/neg/rightassoc-extmethod.check b/tests/neg/rightassoc-extmethod.check new file mode 100644 index 000000000000..a1d2328ed2ff --- /dev/null +++ b/tests/neg/rightassoc-extmethod.check @@ -0,0 +1,8 @@ +-- Error: tests/neg/rightassoc-extmethod.scala:1:23 -------------------------------------------------------------------- +1 |extension (x: Int) def +: (using String): Int = x // error + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | right-associative extension method cannot start with using clause +-- Error: tests/neg/rightassoc-extmethod.scala:2:23 -------------------------------------------------------------------- +2 |extension (x: Int) def *: (y: Int, z: Int) = x // error + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | right-associative extension method must start with a single parameter diff --git a/tests/neg/rightassoc-extmethod.scala b/tests/neg/rightassoc-extmethod.scala new file mode 100644 index 000000000000..4a136ca6eac3 --- /dev/null +++ b/tests/neg/rightassoc-extmethod.scala @@ -0,0 +1,3 @@ +extension (x: Int) def +: (using String): Int = x // error +extension (x: Int) def *: (y: Int, z: Int) = x // error + diff --git a/tests/pos-macros/asExprOf.scala b/tests/pos-macros/asExprOf.scala new file mode 100644 index 000000000000..dd0c4e57a2d0 --- /dev/null +++ b/tests/pos-macros/asExprOf.scala @@ -0,0 +1,7 @@ +import scala.quoted._ + +def test(using Quotes)(x: Expr[_]) = { + import quotes.reflect._ + x.asTerm.asExprOf[Any] +} + diff --git a/tests/pos/extmethods.scala b/tests/pos/extmethods.scala index fe95a1c79b04..368b4f439916 100644 --- a/tests/pos/extmethods.scala +++ b/tests/pos/extmethods.scala @@ -20,3 +20,38 @@ object CollectionStrawMan { protected[this] def newBuilder = new ArrayBuffer[A].mapResult(_.toArray(elemTag)) } } + +extension [A](xs: List[A]) + inline def foldl[B](z: B)(op: (B, A) => B): B = + (xs: List[A]).foldLeft(z)(op) + inline def concat[B <: A](ys: List[B]): List[A] = xs ++ ys + +val x = List("a", "b").foldl[Int](0)((x, y) => x + y.length) +val y = Nil.concat(1 :: Nil) +val y1: List[Int] = y +val z = (1 :: Nil).concat(Nil) +val z1: List[Int] = z + +trait TT: + type A + val m: A + def f[B <: A](x: B): A = if ??? then m else x + +extension (x: TT) + def foo[B <: x.A](y: B) = x.f(y) + +object CC extends TT: + type A = Seq[Int] + val m = Nil + +val xx = CC.foo(List(1, 2, 3)) + +extension (x: TT) + def ff[X](): Int = 1 + def ff[X](s: String): Int = s.length + def ff[X](n: Int): Int = n + +val yy = + CC.ff[Int]() + + CC.ff[String]("abc") + + CC.ff[Int](22) diff --git a/tests/pos/i6900.scala b/tests/pos/i6900.scala index 30a52ff1a01c..55587a18b4ba 100644 --- a/tests/pos/i6900.scala +++ b/tests/pos/i6900.scala @@ -21,15 +21,14 @@ object Test1 { object Test2 { // Works with extension method - extension [A, C](a: A) - def foo: C => A = _ => a + extension [A](a: A) + def foo[C]: C => A = _ => a 1.foo.foo - // ... but have to pass 2 parameters - 1.foo.foo[Any => Int, String] - 1.foo[Int, String].foo - 1.foo[Int, String].foo[String => Int, String] + 1.foo.foo[String] + 1.foo[String].foo + 1.foo[String].foo[String] } diff --git a/tests/pos/reference/delegates.scala b/tests/pos/reference/delegates.scala index 9a05d0717788..88002d939330 100644 --- a/tests/pos/reference/delegates.scala +++ b/tests/pos/reference/delegates.scala @@ -15,11 +15,11 @@ class Common: def unit: T trait Functor[F[_]]: - extension [A, B](x: F[A]) def map (f: A => B): F[B] + extension [A](x: F[A]) def map[B](f: A => B): F[B] trait Monad[F[_]] extends Functor[F]: - extension [A, B](x: F[A]) def flatMap (f: A => F[B]): F[B] - extension [A, B](x: F[A]) def map (f: A => B) = x.flatMap(f `andThen` pure) + extension [A](x: F[A]) def flatMap[B](f: A => F[B]): F[B] + extension [A](x: F[A]) def map[B](f: A => B) = x.flatMap(f `andThen` pure) def pure[A](x: A): F[A] end Common @@ -50,13 +50,13 @@ object Instances extends Common: def third = xs.tail.tail.head given listMonad: Monad[List] with - extension [A, B](xs: List[A]) def flatMap (f: A => List[B]): List[B] = + extension [A](xs: List[A]) def flatMap[B](f: A => List[B]): List[B] = xs.flatMap(f) def pure[A](x: A): List[A] = List(x) given readerMonad[Ctx]: Monad[[X] =>> Ctx => X] with - extension [A, B](r: Ctx => A) def flatMap (f: A => Ctx => B): Ctx => B = + extension [A](r: Ctx => A) def flatMap[B](f: A => Ctx => B): Ctx => B = ctx => f(r(ctx))(ctx) def pure[A](x: A): Ctx => A = ctx => x diff --git a/tests/pos/reference/extension-methods.scala b/tests/pos/reference/extension-methods.scala index 560255a1f8d6..daa187cafa50 100644 --- a/tests/pos/reference/extension-methods.scala +++ b/tests/pos/reference/extension-methods.scala @@ -20,7 +20,7 @@ object ExtMethods: extension [T](xs: List[T]) def second = xs.tail.head - assert(List(1, 2, 3).second[Int] == List(1, 2, 3).second) + assert(second[Int](List(1, 2, 3)) == List(1, 2, 3).second) extension [T: Numeric](x: T) def + (y: T): T = summon[Numeric[T]].plus(x, y) diff --git a/tests/run-bootstrapped/iarray-extmtds.scala b/tests/run-bootstrapped/iarray-extmtds.scala index ddc7610dd794..d075a5c1eca4 100644 --- a/tests/run-bootstrapped/iarray-extmtds.scala +++ b/tests/run-bootstrapped/iarray-extmtds.scala @@ -38,7 +38,7 @@ object Test extends App { assertDifferent(arr1.flatMap(x => List(x, x)), arr1) val twoDArr = IArray(List(1, 2), List(3, 4)) - assertDifferent(twoDArr.flatten[List[Int], Int], twoDArr) + assertDifferent(twoDArr.flatten[Int], twoDArr) println(arr1.fold(0)(_ + _)) diff --git a/tests/run/extension-methods.scala b/tests/run/extension-methods.scala index 04aa06d882eb..38183dcbeccb 100644 --- a/tests/run/extension-methods.scala +++ b/tests/run/extension-methods.scala @@ -85,26 +85,26 @@ object Test extends App { println(max(List(1, 2, 3), List(2))) trait Functor[F[_]] { - extension [A, B](x: F[A]) def map (f: A => B): F[B] + extension [A](x: F[A]) def map[B](f: A => B): F[B] } trait Monad[F[_]] extends Functor[F] { - extension [A, B](x: F[A]) - def flatMap (f: A => F[B]): F[B] - def map (f: A => B) = x.flatMap(f `andThen` pure) + extension [A](x: F[A]) + def flatMap[B](f: A => F[B]): F[B] + def map[B](f: A => B) = x.flatMap(f `andThen` pure) def pure[A](x: A): F[A] } implicit object ListMonad extends Monad[List] { - extension [A, B](xs: List[A]) def flatMap (f: A => List[B]): List[B] = + extension [A](xs: List[A]) def flatMap[B](f: A => List[B]): List[B] = xs.flatMap(f) def pure[A](x: A): List[A] = List(x) } class ReaderMonad[Ctx] extends Monad[[X] =>> Ctx => X] { - extension [A, B](r: Ctx => A) def flatMap (f: A => Ctx => B): Ctx => B = + extension [A](r: Ctx => A) def flatMap[B](f: A => Ctx => B): Ctx => B = ctx => f(r(ctx))(ctx) def pure[A](x: A): Ctx => A = ctx => x @@ -115,6 +115,6 @@ object Test extends App { fs.foldLeft(implicitly[Monad[F]].pure(x))((x: F[T], f: T => T) => if (true) implicitly[Monad[F]].map(x)(f) else if (true) x.map(f) - else x.map[T, T](f) + else x.map[T](f) ) } \ No newline at end of file diff --git a/tests/run/extmethods2.scala b/tests/run/extmethods2.scala index 2f61d36f260c..10b5640c4901 100644 --- a/tests/run/extmethods2.scala +++ b/tests/run/extmethods2.scala @@ -21,8 +21,8 @@ object Test extends App { def third: T = xs.tail.tail.head def concat(ys: List[T]) = xs ++ ys } - extension [T, U](xs: List[T]) { - def zipp(ys: List[U]): List[(T, U)] = xs.zip(ys) + extension [T](xs: List[T]) { + def zipp[U](ys: List[U]): List[(T, U)] = xs.zip(ys) } extension (xs: List[Int]) { def prod = (1 /: xs)(_ * _) @@ -32,14 +32,14 @@ object Test extends App { object B { import A._ val xs = List(1, 2, 3) - assert(xs.second[Int] == 2) + assert(xs.second == 2) assert(xs.third == 3) assert(A.second[Int](xs) == 2) assert(A.third(xs) == 3) assert(xs.prod == 6) assert(xs.concat(xs).length == 6) assert(xs.zipp(xs).map(_ + _).prod == 36) - assert(xs.zipp[Int, Int](xs).map(_ + _).prod == 36) + assert(xs.zipp[Int](xs).map(_ + _).prod == 36) } } diff --git a/tests/run/i9530.check b/tests/run/i9530.check new file mode 100644 index 000000000000..186fd084a859 --- /dev/null +++ b/tests/run/i9530.check @@ -0,0 +1,6 @@ +Expr(123) +123 +Expr(123) +123 +Expr(1234) +1234 diff --git a/tests/run/i9530.scala b/tests/run/i9530.scala new file mode 100644 index 000000000000..e0262764039f --- /dev/null +++ b/tests/run/i9530.scala @@ -0,0 +1,35 @@ +trait Scope: + type Expr + type Value + def expr(x: String): Expr + def value(e: Expr): Value + def combine(e1: Expr, e2: Expr): Expr + +extension (using s: Scope)(expr: s.Expr) + def show = expr.toString + def eval = s.value(expr) + def *: (other: s.Expr) = s.combine(expr, other) + +def f(using s: Scope)(x: s.Expr): (String, s.Value) = + (x.show, x.eval) + +given scope: Scope with + case class Expr(str: String) + type Value = Int + def expr(x: String) = Expr(x) + def value(e: Expr) = e.str.toInt + def combine(e1: Expr, e2: Expr) = Expr(e1.str ++ e2.str) + +@main def Test = + val e = scope.Expr("123") + val (s, v) = f(e) + println(s) + println(v) + val ss = e.show + println(ss) + val vv = e.eval + println(vv) + val e2 = e *: scope.Expr("4") + println(e2.show) + println(e2.eval) + diff --git a/tests/run/instances-anonymous.scala b/tests/run/instances-anonymous.scala index 11fa89c41416..7a42496504ee 100644 --- a/tests/run/instances-anonymous.scala +++ b/tests/run/instances-anonymous.scala @@ -91,25 +91,25 @@ object Test extends App { println(max(List(1, 2, 3), List(2))) trait Functor[F[_]] { - extension [A, B](x: F[A]) def map (f: A => B): F[B] + extension [A](x: F[A]) def map[B](f: A => B): F[B] } trait Monad[F[_]] extends Functor[F] { - extension [A, B](x: F[A]) def flatMap (f: A => F[B]): F[B] - extension [A, B](x: F[A]) def map (f: A => B) = x.flatMap(f `andThen` pure) + extension [A](x: F[A]) def flatMap[B](f: A => F[B]): F[B] + extension [A](x: F[A]) def map[B](f: A => B) = x.flatMap(f `andThen` pure) def pure[A](x: A): F[A] } given Monad[List] with { - extension [A, B](xs: List[A]) def flatMap (f: A => List[B]): List[B] = + extension [A](xs: List[A]) def flatMap[B](f: A => List[B]): List[B] = xs.flatMap(f) def pure[A](x: A): List[A] = List(x) } given [Ctx]: Monad[[X] =>> Ctx => X] with { - extension [A, B](r: Ctx => A) def flatMap (f: A => Ctx => B): Ctx => B = + extension [A](r: Ctx => A) def flatMap[B](f: A => Ctx => B): Ctx => B = ctx => f(r(ctx))(ctx) def pure[A](x: A): Ctx => A = ctx => x @@ -119,6 +119,6 @@ object Test extends App { fs.foldLeft(implicitly[Monad[F]].pure(x))((x: F[T], f: T => T) => if (true) implicitly[Monad[F]].map(x)(f) else if (true) x.map(f) - else x.map[T, T](f) + else x.map[T](f) ) } diff --git a/tests/run/instances.scala b/tests/run/instances.scala index e49896cbba21..128ea0700e02 100644 --- a/tests/run/instances.scala +++ b/tests/run/instances.scala @@ -89,24 +89,24 @@ object Test extends App { println(max(List(1, 2, 3), List(2))) trait Functor[F[_]]: - extension [A, B](x: F[A]) def map (f: A => B): F[B] + extension [A](x: F[A]) def map[B](f: A => B): F[B] end Functor trait Monad[F[_]] extends Functor[F]: - extension [A, B](x: F[A]) def flatMap (f: A => F[B]): F[B] - extension [A, B](x: F[A]) def map (f: A => B) = x.flatMap(f `andThen` pure) + extension [A](x: F[A]) def flatMap[B](f: A => F[B]): F[B] + extension [A](x: F[A]) def map[B](f: A => B) = x.flatMap(f `andThen` pure) def pure[A](x: A): F[A] end Monad given listMonad: Monad[List] with - extension [A, B](xs: List[A]) def flatMap (f: A => List[B]): List[B] = + extension [A](xs: List[A]) def flatMap[B](f: A => List[B]): List[B] = xs.flatMap(f) def pure[A](x: A): List[A] = List(x) given readerMonad[Ctx]: Monad[[X] =>> Ctx => X] with - extension [A, B](r: Ctx => A) def flatMap (f: A => Ctx => B): Ctx => B = + extension [A](r: Ctx => A) def flatMap[B](f: A => Ctx => B): Ctx => B = ctx => f(r(ctx))(ctx) def pure[A](x: A): Ctx => A = ctx => x @@ -115,6 +115,6 @@ object Test extends App { fs.foldLeft(summon[Monad[F]].pure(x))((x: F[T], f: T => T) => if true then summon[Monad[F]].map(x)(f) else if true then x.map(f) - else x.map[T, T](f) + else x.map[T](f) ) } \ No newline at end of file diff --git a/tests/run/singleton-ops-flags.scala b/tests/run/singleton-ops-flags.scala index 66fcc69e21b3..8e2cda6a38c7 100644 --- a/tests/run/singleton-ops-flags.scala +++ b/tests/run/singleton-ops-flags.scala @@ -56,8 +56,9 @@ package example { extension (s: EmptyFlagSet) def next: SingletonFlagSet[0] = 1 extension [N <: Int: ValueOf](s: SingletonFlagSet[N]) def next: SingletonFlagSet[S[N]] = valueOf[N].succ.shift extension [N <: Int: ValueOf](s: SingletonFlagSet[N]) def idx: N = valueOf[N] - extension [N <: Int](s: FlagSet) def toSingletonSets: SingletonSets[N] = s - extension (s: FlagSet) def | (t: FlagSet): FlagSet = s | t + extension (s: FlagSet) + def toSingletonSets[N <: Int]: SingletonSets[N] = s + def | (t: FlagSet): FlagSet = s | t extension [A, N <: Int: ValueOf](ss: SingletonSets[N]) def map(f: [t <: Int] => (s: SingletonFlagSet[t]) => A): List[A] = val maxFlag = valueOf[N]