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

Add quoted pattern type splices #6504

Merged
merged 8 commits into from
Jul 2, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 22 additions & 1 deletion compiler/src/dotty/tools/dotc/ast/Desugar.scala
Original file line number Diff line number Diff line change
Expand Up @@ -818,6 +818,25 @@ object desugar {
}
}

/** Transforms
*
* <mods> type $T >: Low <: Hi
*
* to
*
* @patternBindHole <mods> type $T >: Low <: Hi
*
* if the type is a type splice.
*/
def quotedPatternTypeDef(tree: TypeDef)(implicit ctx: Context): TypeDef = {
assert(ctx.mode.is(Mode.QuotedPattern))
if (tree.name.startsWith("$") && !tree.isBackquoted) {
val patternBindHoleAnnot = New(ref(defn.InternalQuoted_patternBindHoleAnnot.typeRef)).withSpan(tree.span)
val mods = tree.mods.withAddedAnnotation(patternBindHoleAnnot)
tree.withMods(mods)
} else tree
}

/** The normalized name of `mdef`. This means
* 1. Check that the name does not redefine a Scala core class.
* If it does redefine, issue an error and return a mangled name instead of the original one.
Expand Down Expand Up @@ -1031,7 +1050,9 @@ object desugar {
checkModifiers(tree) match {
case tree: ValDef => valDef(tree)
case tree: TypeDef =>
if (tree.isClassDef) classDef(tree) else tree
if (tree.isClassDef) classDef(tree)
else if (ctx.mode.is(Mode.QuotedPattern)) quotedPatternTypeDef(tree)
else tree
case tree: DefDef =>
if (tree.name.isConstructorName) tree // was already handled by enclosing classDef
else defDef(tree)
Expand Down
21 changes: 21 additions & 0 deletions compiler/src/dotty/tools/dotc/ast/TreeMapWithImplicits.scala
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,20 @@ class TreeMapWithImplicits extends tpd.TreeMap {
nestedCtx
}

private def patternScopeCtx(pattern: Tree)(implicit ctx: Context): Context = {
val nestedCtx = ctx.fresh.setNewScope
new TreeTraverser {
def traverse(tree: Tree)(implicit ctx: Context): Unit = {
tree match {
case d: DefTree => nestedCtx.enter(d.symbol)
case _ =>
}
traverseChildren(tree)
}
}.traverse(pattern)
nestedCtx
}

override def transform(tree: Tree)(implicit ctx: Context): Tree = {
def localCtx =
if (tree.hasType && tree.symbol.exists) ctx.withOwner(tree.symbol) else ctx
Expand All @@ -93,6 +107,13 @@ class TreeMapWithImplicits extends tpd.TreeMap {
Nil,
transformSelf(self),
transformStats(impl.body, tree.symbol))
case tree: CaseDef =>
val patCtx = patternScopeCtx(tree.pat)(ctx)
cpy.CaseDef(tree)(
transform(tree.pat),
transform(tree.guard)(patCtx),
transform(tree.body)(patCtx)
)
case _ =>
super.transform(tree)
}
Expand Down
2 changes: 2 additions & 0 deletions compiler/src/dotty/tools/dotc/ast/Trees.scala
Original file line number Diff line number Diff line change
Expand Up @@ -768,6 +768,8 @@ object Trees {

/** Is this a definition of a class? */
def isClassDef: Boolean = rhs.isInstanceOf[Template[_]]

def isBackquoted: Boolean = hasAttachment(Backquoted)
}

/** extends parents { self => body }
Expand Down
13 changes: 12 additions & 1 deletion compiler/src/dotty/tools/dotc/ast/tpd.scala
Original file line number Diff line number Diff line change
Expand Up @@ -1208,7 +1208,7 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
/** An extractor for typed splices */
object Splice {
def apply(tree: Tree)(implicit ctx: Context): Tree = {
val baseType = tree.tpe.baseType(defn.QuotedExprClass)
val baseType = tree.tpe.baseType(defn.QuotedExprClass).orElse(tree.tpe.baseType(defn.QuotedTypeClass))
val argType =
if (baseType != NoType) baseType.argTypesHi.head
else defn.NothingType
Expand Down Expand Up @@ -1342,6 +1342,17 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
}
}

/** Creates the tuple type tree repesentation of the type trees in `ts` */
def tupleTypeTree(elems: List[Tree])(implicit ctx: Context): Tree = {
val arity = elems.length
if (arity <= Definitions.MaxTupleArity && defn.TupleType(arity) != null) AppliedTypeTree(TypeTree(defn.TupleType(arity)), elems)
else nestedPairsTypeTree(elems)
}

/** Creates the nested pairs type tree repesentation of the type trees in `ts` */
nicolasstucki marked this conversation as resolved.
Show resolved Hide resolved
def nestedPairsTypeTree(ts: List[Tree])(implicit ctx: Context): Tree =
ts.foldRight[Tree](TypeTree(defn.UnitType))((x, acc) => AppliedTypeTree(TypeTree(defn.PairType), x :: acc :: Nil))

/** Replaces all positions in `tree` with zero-extent positions */
private def focusPositions(tree: Tree)(implicit ctx: Context): Tree = {
val transformer = new tpd.TreeMap {
Expand Down
4 changes: 2 additions & 2 deletions compiler/src/dotty/tools/dotc/core/Symbols.scala
Original file line number Diff line number Diff line change
Expand Up @@ -210,8 +210,8 @@ trait Symbols { this: Context =>
Nil, decls)

/** Define a new symbol associated with a Bind or pattern wildcard and, by default, make it gadt narrowable. */
def newPatternBoundSymbol(name: Name, info: Type, span: Span, addToGadt: Boolean = true): Symbol = {
val sym = newSymbol(owner, name, Case, info, coord = span)
def newPatternBoundSymbol(name: Name, info: Type, span: Span, addToGadt: Boolean = true, flags: FlagSet = EmptyFlags): Symbol = {
val sym = newSymbol(owner, name, Case | flags, info, coord = span)
if (addToGadt && name.isTypeName) gadt.addToConstraint(sym)
sym
}
Expand Down
11 changes: 8 additions & 3 deletions compiler/src/dotty/tools/dotc/parsing/Parsers.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2644,10 +2644,15 @@ object Parsers {
def typeDefOrDcl(start: Offset, mods: Modifiers): Tree = {
newLinesOpt()
atSpan(start, nameStart) {
val name = ident().toTypeName
val nameIdent = typeIdent()
val tparams = typeParamClauseOpt(ParamOwner.Type)
def makeTypeDef(rhs: Tree): Tree =
finalizeDef(TypeDef(name, lambdaAbstract(tparams, rhs)), mods, start)
def makeTypeDef(rhs: Tree): Tree = {
val rhs1 = lambdaAbstract(tparams, rhs)
val tdef = TypeDef(nameIdent.name.toTypeName, rhs1)
if (nameIdent.isBackquoted)
tdef.pushAttachment(Backquoted, ())
finalizeDef(tdef, mods, start)
}
in.token match {
case EQUALS =>
in.nextToken()
Expand Down
3 changes: 3 additions & 0 deletions compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala
Original file line number Diff line number Diff line change
Expand Up @@ -479,6 +479,7 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) {
if (lo eq hi) optText(lo)(" = " ~ _)
else optText(lo)(" >: " ~ _) ~ optText(hi)(" <: " ~ _)
case Bind(name, body) =>
("given ": Text).provided(tree.symbol.is(Implicit) && !homogenizedView) ~ // Used for scala.quoted.Type in quote patterns (not pickled)
changePrec(InfixPrec) { toText(name) ~ " @ " ~ toText(body) }
case Alternative(trees) =>
changePrec(OrPrec) { toText(trees, " | ") }
Expand Down Expand Up @@ -610,6 +611,8 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) {
else keywordStr("'{") ~ toTextGlobal(dropBlock(tree)) ~ keywordStr("}")
case Splice(tree) =>
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 Thicket(trees) =>
Expand Down
9 changes: 9 additions & 0 deletions compiler/src/dotty/tools/dotc/tastyreflect/KernelImpl.scala
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,15 @@ class KernelImpl(val rootContext: core.Contexts.Context, val rootPosition: util.

def Context_source(self: Context): java.nio.file.Path = self.compilationUnit.source.file.jpath

def Context_GADT_setFreshGADTBounds(self: Context): Context =
self.fresh.setFreshGADTBounds.addMode(Mode.GadtConstraintInference)

def Context_GADT_addToConstraint(self: Context)(syms: List[Symbol]): Boolean =
self.gadt.addToConstraint(syms)

def Context_GADT_approximation(self: Context)(sym: Symbol, fromBelow: Boolean): Type =
self.gadt.approximation(sym, fromBelow)

//
// REPORTING
//
Expand Down
Loading