Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Allow leading context parameters in extension methods #10940

Merged
merged 28 commits into from
Jan 6, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
9a57e14
Allow leading context parameters in extension methods
odersky Dec 28, 2020
dc71243
Fix scala3doc test
odersky Dec 28, 2020
7b24c5a
Refine encoding of right-associative extension methods
odersky Dec 28, 2020
e6afdbc
Fix wording according to review suggestions
odersky Dec 29, 2020
dbc572c
Make polyDefDef pass type trees instead of types
odersky Dec 29, 2020
2526295
make tpd.appliedToArgss also work for type arguments
odersky Dec 29, 2020
380c80b
Improve handling of parameters in Tasty format
odersky Dec 30, 2020
6118594
Merge type params and term params in DefDef nodes
odersky Dec 30, 2020
1eff2f4
Optimize termParamss
odersky Dec 31, 2020
d4d604d
Use single parameter list for tpd.DefDef methods
odersky Dec 31, 2020
5a233c9
Eliminate polyDefDef def and calls
odersky Dec 31, 2020
6ea2da2
Allow two type parameter lists in extension methods
odersky Jan 1, 2021
7c159f8
Disable macro tests
odersky Jan 1, 2021
5f717d0
Workaround for community-build failure
odersky Jan 1, 2021
d5d3f23
Update reference docs
odersky Jan 1, 2021
1662016
Fix definition of asExprOf on Tree
nicolasstucki Jan 4, 2021
fbcf807
Update extension docs
odersky Jan 4, 2021
02e7298
Drop IntegratedTypeArgs
odersky Jan 4, 2021
f657212
Fix inlining with multiple type argument clauses
odersky Jan 4, 2021
3a00189
Add tests with dependencies from second type parameter clause
odersky Jan 4, 2021
36b1a71
Make overloading resolution work for embedded type params
odersky Jan 4, 2021
9528eef
Fix right associative extension method docs
prolativ Dec 29, 2020
29f671b
Fix problem with extension methods in givens
odersky Jan 5, 2021
d6b4bee
Use `unreachable` for match cases that are known to be unreachable
odersky Jan 5, 2021
e0eed74
Revert patches of asExprOf
nicolasstucki Jan 5, 2021
96fd018
Remove outdated comments
nicolasstucki Jan 5, 2021
5c4c412
Revert changes in BootstrappedOnlyCompilationTests
nicolasstucki Jan 6, 2021
c4b210e
Remove outdated comments
nicolasstucki Jan 6, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion community-build/community-projects/intent
Original file line number Diff line number Diff line change
Expand Up @@ -55,14 +55,14 @@ class QuotesImpl private (using val ctx: Context) extends Quotes, QuoteUnpickler

end extension

extension [X](self: scala.quoted.Expr[Any])
extension (self: scala.quoted.Expr[Any])
/** Checks is the `quoted.Expr[?]` is valid expression of type `X` */
def isExprOf(using scala.quoted.Type[X]): Boolean =
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(using scala.quoted.Type[X]): scala.quoted.Expr[X] = {
if isExprOf[X] then
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(
Expand Down Expand Up @@ -107,9 +107,9 @@ class QuotesImpl private (using val ctx: Context) extends Quotes, QuoteUnpickler
case _ => throw new Exception("Expected a Term but was: " + self)
end extension

extension [T](self: Tree)
def asExprOf(using tp: scala.quoted.Type[T]): scala.quoted.Expr[T] =
QuotesImpl.this.asExprOf[T](self.asExpr)(using tp)
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)
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,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(
Expand Down Expand Up @@ -255,17 +255,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
Expand Down Expand Up @@ -378,7 +381,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
}

Expand Down Expand Up @@ -2653,6 +2656,7 @@ class QuotesImpl private (using val ctx: Context) extends Quotes, QuoteUnpickler
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
Expand All @@ -2667,6 +2671,7 @@ class QuotesImpl private (using val ctx: Context) extends Quotes, QuoteUnpickler
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
Expand Down Expand Up @@ -2863,8 +2868,11 @@ class QuotesImpl private (using val ctx: Context) extends Quotes, QuoteUnpickler
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 =>
Expand Down
6 changes: 3 additions & 3 deletions compiler/src/dotty/tools/backend/jvm/BCodeSkelBuilder.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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.")
Expand Down
2 changes: 1 addition & 1 deletion compiler/src/dotty/tools/backend/sjs/JSCodeGen.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down
Loading