From 22c1e0ea7409a7d6f5170325797ff279ad2d8e4d Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Sun, 31 Mar 2019 14:13:07 +0200 Subject: [PATCH 01/12] Add Quoted.Matcher.unapply to Definitions Also, cleanup some other stuff. Not done with this yet, but it is crucial that we follow the same pattern everywhere in Definition, or otherwise people will get hopelessly confused. Right now some of the more recent additions use naming conventions that deviate from what was intended. --- .../dotty/tools/dotc/core/Definitions.scala | 36 +++++++------------ 1 file changed, 13 insertions(+), 23 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/Definitions.scala b/compiler/src/dotty/tools/dotc/core/Definitions.scala index 9b0f5c0f69d7..40b03f790419 100644 --- a/compiler/src/dotty/tools/dotc/core/Definitions.scala +++ b/compiler/src/dotty/tools/dotc/core/Definitions.scala @@ -705,13 +705,13 @@ class Definitions { lazy val QuotedExprType: TypeRef = ctx.requiredClassRef("scala.quoted.Expr") def QuotedExprClass(implicit ctx: Context): ClassSymbol = QuotedExprType.symbol.asClass - lazy val InternalQuotedModule: TermRef = ctx.requiredModuleRef("scala.internal.Quoted") - def InternalQuotedModuleClass: Symbol = InternalQuotedModule.symbol - lazy val InternalQuoted_exprQuoteR: TermRef = InternalQuotedModuleClass.requiredMethodRef("exprQuote".toTermName) + lazy val InternalQuotedModuleRef: TermRef = ctx.requiredModuleRef("scala.internal.Quoted") + def InternalQuotedModule: Symbol = InternalQuotedModuleRef.symbol + lazy val InternalQuoted_exprQuoteR: TermRef = InternalQuotedModule.requiredMethodRef("exprQuote".toTermName) def InternalQuoted_exprQuote(implicit ctx: Context): Symbol = InternalQuoted_exprQuoteR.symbol - lazy val InternalQuoted_exprSpliceR: TermRef = InternalQuotedModuleClass.requiredMethodRef("exprSplice".toTermName) + lazy val InternalQuoted_exprSpliceR: TermRef = InternalQuotedModule.requiredMethodRef("exprSplice".toTermName) def InternalQuoted_exprSplice(implicit ctx: Context): Symbol = InternalQuoted_exprSpliceR.symbol - lazy val InternalQuoted_typeQuoteR: TermRef = InternalQuotedModuleClass.requiredMethodRef("typeQuote".toTermName) + lazy val InternalQuoted_typeQuoteR: TermRef = InternalQuotedModule.requiredMethodRef("typeQuote".toTermName) def InternalQuoted_typeQuote(implicit ctx: Context): Symbol = InternalQuoted_typeQuoteR.symbol lazy val QuotedExprsModule: TermSymbol = ctx.requiredModule("scala.quoted.Exprs") @@ -723,24 +723,8 @@ class Definitions { lazy val QuotedType_spliceR: TypeRef = QuotedTypeClass.requiredType(tpnme.splice).typeRef def QuotedType_splice : Symbol = QuotedType_spliceR.symbol - lazy val QuotedTypeModuleType: TermRef = ctx.requiredModuleRef("scala.quoted.Type") - def QuotedTypeModule(implicit ctx: Context): Symbol = QuotedTypeModuleType.symbol - - lazy val QuotedLiftableModule: TermSymbol = ctx.requiredModule("scala.quoted.Liftable") - def QuotedLiftableModuleClass(implicit ctx: Context): ClassSymbol = QuotedLiftableModule.asClass - - def QuotedLiftable_BooleanIsLiftable: TermRef = QuotedLiftableModule.requiredMethodRef("BooleanIsLiftable") - def QuotedLiftable_ByteIsLiftable: TermRef = QuotedLiftableModule.requiredMethodRef("ByteIsLiftable") - def QuotedLiftable_CharIsLiftable: TermRef = QuotedLiftableModule.requiredMethodRef("CharIsLiftable") - def QuotedLiftable_ShortIsLiftable: TermRef = QuotedLiftableModule.requiredMethodRef("ShortIsLiftable") - def QuotedLiftable_IntIsLiftable: TermRef = QuotedLiftableModule.requiredMethodRef("IntIsLiftable") - def QuotedLiftable_LongIsLiftable: TermRef = QuotedLiftableModule.requiredMethodRef("LongIsLiftable") - def QuotedLiftable_FloatIsLiftable: TermRef = QuotedLiftableModule.requiredMethodRef("FloatIsLiftable") - def QuotedLiftable_DoubleIsLiftable: TermRef = QuotedLiftableModule.requiredMethodRef("DoubleIsLiftable") - def QuotedLiftable_StringIsLiftable: TermRef = QuotedLiftableModule.requiredMethodRef("StringIsLiftable") - - lazy val QuotedLiftableType: TypeRef = ctx.requiredClassRef("scala.quoted.Liftable") - def QuotedLiftableClass(implicit ctx: Context): ClassSymbol = QuotedLiftableType.symbol.asClass + lazy val QuotedTypeModuleRef: TermRef = ctx.requiredModuleRef("scala.quoted.Type") + def QuotedTypeModule(implicit ctx: Context): Symbol = QuotedTypeModuleRef.symbol def Unpickler_unpickleExpr: TermSymbol = ctx.requiredMethod("scala.runtime.quoted.Unpickler.unpickleExpr") def Unpickler_liftedExpr: TermSymbol = ctx.requiredMethod("scala.runtime.quoted.Unpickler.liftedExpr") @@ -752,6 +736,12 @@ class Definitions { lazy val TastyReflectionModule: TermSymbol = ctx.requiredModule("scala.tasty.Reflection") lazy val TastyReflection_macroContext: TermSymbol = TastyReflectionModule.requiredMethod("macroContext") + lazy val QuotedMatcherModuleRef: TermRef = ctx.requiredModuleRef("scala.runtime.quoted.Matcher") + def QuotedMatcherModule(implicit ctx: Context): Symbol = QuotedMatcherModuleRef.symbol + + lazy val QuotedMatcher_unapplyR: TermRef = QuotedMatcherModule.requiredMethodRef(nme.unapply) + def QuotedMatcher_unapply(implicit ctx: Context) = QuotedMatcher_unapplyR.symbol + lazy val EqlType: TypeRef = ctx.requiredClassRef("scala.Eql") def EqlClass(implicit ctx: Context): ClassSymbol = EqlType.symbol.asClass def EqlModule(implicit ctx: Context): Symbol = EqlClass.companionModule From 72883e9d719b9122b3c7e75b251f1ecb211d4a9e Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Sun, 31 Mar 2019 14:14:25 +0200 Subject: [PATCH 02/12] Add tupleOf utility method --- compiler/src/dotty/tools/dotc/core/TypeOps.scala | 5 +++++ compiler/src/dotty/tools/dotc/transform/TypeUtils.scala | 4 ++-- compiler/src/dotty/tools/dotc/typer/Deriving.scala | 4 ++-- compiler/src/dotty/tools/dotc/typer/Typer.scala | 2 +- 4 files changed, 10 insertions(+), 5 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/TypeOps.scala b/compiler/src/dotty/tools/dotc/core/TypeOps.scala index 3d5482701ce8..b1dd4812a63b 100644 --- a/compiler/src/dotty/tools/dotc/core/TypeOps.scala +++ b/compiler/src/dotty/tools/dotc/core/TypeOps.scala @@ -567,4 +567,9 @@ trait TypeOps { this: Context => // TODO: Make standalone object. object TypeOps { @sharable var track: Boolean = false // !!!DEBUG + + // TODO: Move other typeops here. It's a bit weird that they are a part of `ctx` + + def tupleOf(ts: List[Type])(implicit ctx: Context): Type = + (ts :\ (defn.UnitType: Type))(defn.PairType.appliedTo(_, _)) } diff --git a/compiler/src/dotty/tools/dotc/transform/TypeUtils.scala b/compiler/src/dotty/tools/dotc/transform/TypeUtils.scala index 839fa32892fb..509130df40e2 100644 --- a/compiler/src/dotty/tools/dotc/transform/TypeUtils.scala +++ b/compiler/src/dotty/tools/dotc/transform/TypeUtils.scala @@ -48,8 +48,8 @@ object TypeUtils { else throw new AssertionError("not a tuple") } - /** The `*:` equivalent of an instantce of a Tuple class */ + /** The `*:` equivalent of an instance of a Tuple class */ def toNestedPairs(implicit ctx: Context): Type = - (tupleElementTypes :\ (defn.UnitType: Type))(defn.PairType.appliedTo(_, _)) + TypeOps.tupleOf(tupleElementTypes) } } diff --git a/compiler/src/dotty/tools/dotc/typer/Deriving.scala b/compiler/src/dotty/tools/dotc/typer/Deriving.scala index 24f20cc8c5df..0dea4ebcba49 100644 --- a/compiler/src/dotty/tools/dotc/typer/Deriving.scala +++ b/compiler/src/dotty/tools/dotc/typer/Deriving.scala @@ -78,14 +78,14 @@ trait Deriving { this: Typer => case _ => (sym.termRef, Nil) } - val elemShape = (elems :\ (defn.UnitType: Type))(defn.PairType.appliedTo(_, _)) + val elemShape = TypeOps.tupleOf(elems) defn.ShapeCaseType.appliedTo(constr, elemShape) } /** The shape of `cls` if `cls` is sealed */ private def sealedShape: Type = { val cases = children.map(caseShape).filter(_.exists) - val casesShape = (cases :\ (defn.UnitType: Type))(defn.PairType.appliedTo(_, _)) + val casesShape = TypeOps.tupleOf(cases) defn.ShapeCasesType.appliedTo(casesShape) } diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala index 48171be2327a..fdc97acc0a89 100644 --- a/compiler/src/dotty/tools/dotc/typer/Typer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala @@ -1919,7 +1919,7 @@ class Typer extends Namer else { val elemTpes = (elems, pts).zipped.map((elem, pt) => ctx.typeComparer.widenInferred(elem.tpe, pt)) - val resTpe = (elemTpes :\ (defn.UnitType: Type))(defn.PairType.appliedTo(_, _)) + val resTpe = TypeOps.tupleOf(elemTpes) app1.cast(resTpe) } } From 8f37686e4e6358e084b6576e045bf9fc145dd94a Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Sun, 31 Mar 2019 14:22:58 +0200 Subject: [PATCH 03/12] Quote patterns: syntax and parsing --- compiler/src/dotty/tools/dotc/parsing/Parsers.scala | 8 ++++++-- docs/docs/internals/syntax.md | 6 ++++-- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala index 93a3a1e9c9d5..bbdf9fa97926 100644 --- a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala +++ b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala @@ -1478,9 +1478,8 @@ object Parsers { /** SimpleExpr ::= ‘new’ (ConstrApp [TemplateBody] | TemplateBody) * | BlockExpr - * | ‘'’ ‘{’ Block ‘}’ - * | ‘'’ ‘[’ Type ‘]’ * | ‘$’ ‘{’ Block ‘}’ + * | Quoted * | quoteId * | SimpleExpr1 [`_'] * SimpleExpr1 ::= literal @@ -1490,6 +1489,8 @@ object Parsers { * | SimpleExpr `.' id * | SimpleExpr (TypeArgs | NamedTypeArgs) * | SimpleExpr1 ArgumentExprs + * Quoted ::= ‘'’ ‘{’ Block ‘}’ + * | ‘'’ ‘[’ Type ‘]’ */ def simpleExpr(): Tree = { var canApply = true @@ -1827,6 +1828,7 @@ object Parsers { /** SimplePattern ::= PatVar * | Literal + * | Quoted * | XmlPattern * | `(' [Patterns] `)' * | SimplePattern1 [TypeArgs] [ArgumentPatterns] @@ -1853,6 +1855,8 @@ object Parsers { } else wildIndent case LPAREN => atSpan(in.offset) { makeTupleOrParens(inParens(patternsOpt())) } + case QUOTE => + simpleExpr() case XMLSTART => xmlLiteralPattern() case _ => diff --git a/docs/docs/internals/syntax.md b/docs/docs/internals/syntax.md index 9e3bf68924c9..74a9d33715d1 100644 --- a/docs/docs/internals/syntax.md +++ b/docs/docs/internals/syntax.md @@ -209,9 +209,8 @@ InfixExpr ::= PrefixExpr PrefixExpr ::= [‘-’ | ‘+’ | ‘~’ | ‘!’] SimpleExpr PrefixOp(expr, op) SimpleExpr ::= ‘new’ (ConstrApp [TemplateBody] | TemplateBody) New(constr | templ) | BlockExpr - | ‘'’ ‘{’ Block ‘}’ - | ‘'’ ‘[’ Type ‘]’ | ‘$’ ‘{’ Block ‘}’ + | Quoted | quoteId // only inside splices | SimpleExpr1 [‘_’] PostfixOp(expr, _) SimpleExpr1 ::= Literal @@ -222,6 +221,8 @@ SimpleExpr1 ::= Literal | SimpleExpr (TypeArgs | NamedTypeArgs) TypeApply(expr, args) | SimpleExpr1 ArgumentExprs Apply(expr, args) | XmlExpr +Quoted ::= ‘'’ ‘{’ Block ‘}’ + | ‘'’ ‘[’ Type ‘]’ ExprsInParens ::= ExprInParens {‘,’ ExprInParens} ExprInParens ::= PostfixExpr ‘:’ Type | Expr @@ -261,6 +262,7 @@ InfixPattern ::= SimplePattern { id [nl] SimplePattern } SimplePattern ::= PatVar Ident(wildcard) | Literal Bind(name, Ident(wildcard)) | ‘(’ [Patterns] ‘)’ Parens(pats) Tuple(pats) + | Quoted | XmlPattern | SimplePattern1 [TypeArgs] [ArgumentPatterns] SimplePattern1 ::= Path From a8d761533c4b1982338f51bddd6a88db81430456 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Sun, 31 Mar 2019 14:26:08 +0200 Subject: [PATCH 04/12] Quoted patterns: type checking --- compiler/src/dotty/tools/dotc/ast/tpd.scala | 10 ++++ compiler/src/dotty/tools/dotc/ast/untpd.scala | 8 +-- compiler/src/dotty/tools/dotc/core/Mode.scala | 3 ++ .../src/dotty/tools/dotc/typer/Typer.scala | 53 ++++++++++++++++--- .../src/scala/runtime/quoted/Matcher.scala | 10 ++++ tests/pos/quotedPatterns.scala | 9 ++++ 6 files changed, 83 insertions(+), 10 deletions(-) create mode 100644 library/src/scala/runtime/quoted/Matcher.scala create mode 100644 tests/pos/quotedPatterns.scala diff --git a/compiler/src/dotty/tools/dotc/ast/tpd.scala b/compiler/src/dotty/tools/dotc/ast/tpd.scala index 0bc50597d7b9..1594c05b29b8 100644 --- a/compiler/src/dotty/tools/dotc/ast/tpd.scala +++ b/compiler/src/dotty/tools/dotc/ast/tpd.scala @@ -1178,6 +1178,16 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo { } } + /** An extractor for typed splices */ + object Splice { + def apply(tree: Tree)(implicit ctx: Context): Tree = + ref(defn.InternalQuoted_exprSplice).appliedTo(tree) + def unapply(tree: Tree)(implicit ctx: Context): Option[Tree] = tree match { + case Apply(fn, arg :: Nil) if fn.symbol == defn.InternalQuoted_exprSplice => Some(arg) + case _ => None + } + } + /** A key to be used in a context property that tracks enclosing inlined calls */ private val InlinedCalls = new 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 4c51d26fce69..f95e4b37adce 100644 --- a/compiler/src/dotty/tools/dotc/ast/untpd.scala +++ b/compiler/src/dotty/tools/dotc/ast/untpd.scala @@ -93,7 +93,7 @@ object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo { override def isType: Boolean = !isTerm } case class Throw(expr: Tree)(implicit @constructorOnly src: SourceFile) extends TermTree - case class Quote(t: Tree)(implicit @constructorOnly src: SourceFile) extends TermTree + case class Quote(quoted: Tree)(implicit @constructorOnly src: SourceFile) extends TermTree case class Splice(expr: Tree)(implicit @constructorOnly src: SourceFile) extends TermTree case class TypSplice(expr: Tree)(implicit @constructorOnly src: SourceFile) extends TypTree case class DoWhile(body: Tree, cond: Tree)(implicit @constructorOnly src: SourceFile) extends TermTree @@ -492,9 +492,9 @@ object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo { case tree: Throw if expr eq tree.expr => tree case _ => finalize(tree, untpd.Throw(expr)(tree.source)) } - def Quote(tree: Tree)(t: Tree)(implicit ctx: Context): Tree = tree match { - case tree: Quote if t eq tree.t => tree - case _ => finalize(tree, untpd.Quote(t)(tree.source)) + def Quote(tree: Tree)(quoted: Tree)(implicit ctx: Context): Tree = tree match { + case tree: Quote if quoted eq tree.quoted => tree + case _ => finalize(tree, untpd.Quote(quoted)(tree.source)) } def Splice(tree: Tree)(expr: Tree)(implicit ctx: Context): Tree = tree match { case tree: Splice if expr eq tree.expr => tree diff --git a/compiler/src/dotty/tools/dotc/core/Mode.scala b/compiler/src/dotty/tools/dotc/core/Mode.scala index 1aa2c0f6f1ba..430d0b062c84 100644 --- a/compiler/src/dotty/tools/dotc/core/Mode.scala +++ b/compiler/src/dotty/tools/dotc/core/Mode.scala @@ -104,4 +104,7 @@ object Mode { /** Are we trying to find a hidden implicit? */ val FindHiddenImplicits: Mode = newMode(24, "FindHiddenImplicits") + + /** Are we in a quote in a pattern? */ + val QuotedPattern: Mode = newMode(25, "QuotedPattern") } diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala index fdc97acc0a89..9d941239e9b6 100644 --- a/compiler/src/dotty/tools/dotc/typer/Typer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala @@ -1930,17 +1930,51 @@ class Typer extends Namer * while tracking the quotation level in the context. */ def typedQuote(tree: untpd.Quote, pt: Type)(implicit ctx: Context): Tree = track("typedQuote") { - tree.t match { + tree.quoted match { case untpd.Splice(innerExpr) => ctx.warning("Canceled splice directly inside a quote. '{ ${ XYZ } } is equivalent to XYZ.", tree.sourcePos) typed(innerExpr, pt) - case t if t.isType => - typedTypeApply(untpd.TypeApply(untpd.ref(defn.InternalQuoted_typeQuoteR), List(tree.t)), pt)(quoteContext).withSpan(tree.span) - case t=> - typedApply(untpd.Apply(untpd.ref(defn.InternalQuoted_exprQuoteR), tree.t), pt)(quoteContext).withSpan(tree.span) + case quoted if quoted.isType => + typedTypeApply(untpd.TypeApply(untpd.ref(defn.InternalQuoted_typeQuoteR), quoted :: Nil), pt)(quoteContext).withSpan(tree.span) + case quoted => + if (ctx.mode.is(Mode.Pattern)) { + val exprPt = pt.baseType(defn.QuotedExprClass) + val quotedPt = if (exprPt.exists) exprPt.argTypesHi.head else defn.AnyType + val quoted1 = typedExpr(quoted, quotedPt)(quoteContext.addMode(Mode.QuotedPattern)) + val (shape, splices) = splitQuotePattern(quoted1) + val splicePat = typed(untpd.Tuple(splices.map(untpd.TypedSplice(_))).withSpan(quoted.span)) + val patType = TypeOps.tupleOf(splices.tpes) + UnApply( + ref(defn.QuotedMatcher_unapplyR).appliedToType(patType), + ref(defn.InternalQuoted_exprQuoteR).appliedToType(shape.tpe).appliedTo(shape) :: givenReflection :: Nil, + splicePat :: Nil, + pt) + } + else + typedApply(untpd.Apply(untpd.ref(defn.InternalQuoted_exprQuoteR), quoted), pt)(quoteContext).withSpan(tree.span) + } + } + + def splitQuotePattern(quoted: Tree)(implicit ctx: Context): (Tree, List[Tree]) = { + object splitter extends tpd.TreeMap { + val patBuf = new mutable.ListBuffer[Tree] + override def transform(tree: Tree)(implicit ctx: Context) = tree match { + case Typed(Splice(pat), tpt) => + val exprTpt = ref(defn.QuotedExprType).appliedToTypeTrees(tpt :: Nil) + transform(Splice(Typed(pat, exprTpt))) + case Splice(pat) => + try tasty.TreePickler.Hole(patBuf.length, Nil) + finally patBuf += pat + case _ => + super.transform(tree) + } } + val result = splitter.transform(quoted) + (result, splitter.patBuf.toList) } + def givenReflection(implicit ctx: Context): Tree = Literal(Constant(null)) // FIXME: fill in + /** Translate `${ t: Expr[T] }` into expression `t.splice` while tracking the quotation level in the context */ def typedSplice(tree: untpd.Splice, pt: Type)(implicit ctx: Context): Tree = track("typedSplice") { checkSpliceOutsideQuote(tree) @@ -1949,7 +1983,14 @@ class Typer extends Namer ctx.warning("Canceled quote directly inside a splice. ${ '{ XYZ } } is equivalent to XYZ.", tree.sourcePos) typed(innerExpr, pt) case expr => - typedApply(untpd.Apply(untpd.ref(defn.InternalQuoted_exprSpliceR), tree.expr), pt)(spliceContext).withSpan(tree.span) + if (ctx.mode.is(Mode.QuotedPattern)) { + fullyDefinedType(pt, "quoted pattern selector", tree.span) + val pat = typedPattern(expr, defn.QuotedExprType.appliedTo(pt))( + spliceContext.retractMode(Mode.QuotedPattern)) + Splice(pat) + } + else + typedApply(untpd.Apply(untpd.ref(defn.InternalQuoted_exprSpliceR), tree.expr), pt)(spliceContext).withSpan(tree.span) } } diff --git a/library/src/scala/runtime/quoted/Matcher.scala b/library/src/scala/runtime/quoted/Matcher.scala new file mode 100644 index 000000000000..b77baec24aec --- /dev/null +++ b/library/src/scala/runtime/quoted/Matcher.scala @@ -0,0 +1,10 @@ +package scala.runtime.quoted + +import scala.quoted.Expr +import scala.tasty.Reflection + +/** THIS IS A PLACEHOLDER + */ +object Matcher { + def unapply[Tup <: Tuple](scrut: Expr[_])(implicit pattern: Expr[_], reflection: Reflection): Option[Tup] = ??? +} diff --git a/tests/pos/quotedPatterns.scala b/tests/pos/quotedPatterns.scala new file mode 100644 index 000000000000..aa72172c64af --- /dev/null +++ b/tests/pos/quotedPatterns.scala @@ -0,0 +1,9 @@ +object Test { + + val x = '{1 + 2} + + x match { + case '{1 + 2} => + case _ => + } +} \ No newline at end of file From c266bc95e0a1289cb2aae076e3fe47080da8c391 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Sun, 31 Mar 2019 15:31:19 +0200 Subject: [PATCH 05/12] Handle splices in quoted patterns --- compiler/src/dotty/tools/dotc/ast/tpd.scala | 6 ++++-- compiler/src/dotty/tools/dotc/typer/Typer.scala | 9 ++++++++- tests/pos/quotedPatterns.scala | 6 ++++-- 3 files changed, 16 insertions(+), 5 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/ast/tpd.scala b/compiler/src/dotty/tools/dotc/ast/tpd.scala index 1594c05b29b8..c9d884ac673c 100644 --- a/compiler/src/dotty/tools/dotc/ast/tpd.scala +++ b/compiler/src/dotty/tools/dotc/ast/tpd.scala @@ -1180,8 +1180,10 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo { /** An extractor for typed splices */ object Splice { - def apply(tree: Tree)(implicit ctx: Context): Tree = - ref(defn.InternalQuoted_exprSplice).appliedTo(tree) + def apply(tree: Tree)(implicit ctx: Context): Tree = { + val argType = tree.tpe.baseType(defn.QuotedExprClass).argTypesHi.head + ref(defn.InternalQuoted_exprSplice).appliedToType(argType).appliedTo(tree) + } def unapply(tree: Tree)(implicit ctx: Context): Option[Tree] = tree match { case Apply(fn, arg :: Nil) if fn.symbol == defn.InternalQuoted_exprSplice => Some(arg) case _ => None diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala index 9d941239e9b6..98a64dfb3477 100644 --- a/compiler/src/dotty/tools/dotc/typer/Typer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala @@ -1963,7 +1963,7 @@ class Typer extends Namer val exprTpt = ref(defn.QuotedExprType).appliedToTypeTrees(tpt :: Nil) transform(Splice(Typed(pat, exprTpt))) case Splice(pat) => - try tasty.TreePickler.Hole(patBuf.length, Nil) + try holeForSplice(tree) finally patBuf += pat case _ => super.transform(tree) @@ -1973,6 +1973,13 @@ class Typer extends Namer (result, splitter.patBuf.toList) } + // TODO: Currently, a hole is expressed as interal.quoted.ExprSplice[T](???) + // Settle on a different representation and apply Stagin + def holeForSplice(splice: Tree)(implicit ctx: Context): Tree = { + val Apply(fn, arg) = splice + tpd.cpy.Apply(splice)(fn, ref(defn.Predef_undefined) :: Nil) + } + def givenReflection(implicit ctx: Context): Tree = Literal(Constant(null)) // FIXME: fill in /** Translate `${ t: Expr[T] }` into expression `t.splice` while tracking the quotation level in the context */ diff --git a/tests/pos/quotedPatterns.scala b/tests/pos/quotedPatterns.scala index aa72172c64af..ef340a02972e 100644 --- a/tests/pos/quotedPatterns.scala +++ b/tests/pos/quotedPatterns.scala @@ -2,8 +2,10 @@ object Test { val x = '{1 + 2} + def f(x: Int) = x + x match { - case '{1 + 2} => - case _ => + case '{1 + 2} => 0 + case '{f($x)} => x } } \ No newline at end of file From 2de84b0d9566af508966525446dfa6eb6a357967 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Sun, 31 Mar 2019 19:12:00 +0200 Subject: [PATCH 06/12] Improve treatment of quoted pattern holes --- .../src/dotty/tools/dotc/core/Definitions.scala | 8 +++++--- compiler/src/dotty/tools/dotc/typer/Typer.scala | 15 ++++++--------- .../src-bootstrapped/scala/internal/Quoted.scala | 3 +++ tests/pos/quotedPatterns.scala | 8 +++++--- 4 files changed, 19 insertions(+), 15 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/Definitions.scala b/compiler/src/dotty/tools/dotc/core/Definitions.scala index 40b03f790419..014561661221 100644 --- a/compiler/src/dotty/tools/dotc/core/Definitions.scala +++ b/compiler/src/dotty/tools/dotc/core/Definitions.scala @@ -707,12 +707,14 @@ class Definitions { lazy val InternalQuotedModuleRef: TermRef = ctx.requiredModuleRef("scala.internal.Quoted") def InternalQuotedModule: Symbol = InternalQuotedModuleRef.symbol - lazy val InternalQuoted_exprQuoteR: TermRef = InternalQuotedModule.requiredMethodRef("exprQuote".toTermName) + lazy val InternalQuoted_exprQuoteR: TermRef = InternalQuotedModule.requiredMethodRef("exprQuote") def InternalQuoted_exprQuote(implicit ctx: Context): Symbol = InternalQuoted_exprQuoteR.symbol - lazy val InternalQuoted_exprSpliceR: TermRef = InternalQuotedModule.requiredMethodRef("exprSplice".toTermName) + lazy val InternalQuoted_exprSpliceR: TermRef = InternalQuotedModule.requiredMethodRef("exprSplice") def InternalQuoted_exprSplice(implicit ctx: Context): Symbol = InternalQuoted_exprSpliceR.symbol - lazy val InternalQuoted_typeQuoteR: TermRef = InternalQuotedModule.requiredMethodRef("typeQuote".toTermName) + lazy val InternalQuoted_typeQuoteR: TermRef = InternalQuotedModule.requiredMethodRef("typeQuote") def InternalQuoted_typeQuote(implicit ctx: Context): Symbol = InternalQuoted_typeQuoteR.symbol + lazy val InternalQuoted_patternHoleR: TermRef = InternalQuotedModule.requiredMethodRef("patternHole") + def InternalQuoted_patternHole(implicit ctx: Context): Symbol = InternalQuoted_patternHoleR.symbol lazy val QuotedExprsModule: TermSymbol = ctx.requiredModule("scala.quoted.Exprs") def QuotedExprsClass(implicit ctx: Context): ClassSymbol = QuotedExprsModule.asClass diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala index 98a64dfb3477..ea9a470c3f06 100644 --- a/compiler/src/dotty/tools/dotc/typer/Typer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala @@ -1943,7 +1943,7 @@ class Typer extends Namer val quoted1 = typedExpr(quoted, quotedPt)(quoteContext.addMode(Mode.QuotedPattern)) val (shape, splices) = splitQuotePattern(quoted1) val splicePat = typed(untpd.Tuple(splices.map(untpd.TypedSplice(_))).withSpan(quoted.span)) - val patType = TypeOps.tupleOf(splices.tpes) + val patType = TypeOps.tupleOf(splices.tpes.map(_.widen)) UnApply( ref(defn.QuotedMatcher_unapplyR).appliedToType(patType), ref(defn.InternalQuoted_exprQuoteR).appliedToType(shape.tpe).appliedTo(shape) :: givenReflection :: Nil, @@ -1960,10 +1960,10 @@ class Typer extends Namer val patBuf = new mutable.ListBuffer[Tree] override def transform(tree: Tree)(implicit ctx: Context) = tree match { case Typed(Splice(pat), tpt) => - val exprTpt = ref(defn.QuotedExprType).appliedToTypeTrees(tpt :: Nil) + val exprTpt = AppliedTypeTree(TypeTree(defn.QuotedExprType), tpt :: Nil) transform(Splice(Typed(pat, exprTpt))) case Splice(pat) => - try holeForSplice(tree) + try patternHole(tree) finally patBuf += pat case _ => super.transform(tree) @@ -1973,12 +1973,9 @@ class Typer extends Namer (result, splitter.patBuf.toList) } - // TODO: Currently, a hole is expressed as interal.quoted.ExprSplice[T](???) - // Settle on a different representation and apply Stagin - def holeForSplice(splice: Tree)(implicit ctx: Context): Tree = { - val Apply(fn, arg) = splice - tpd.cpy.Apply(splice)(fn, ref(defn.Predef_undefined) :: Nil) - } + /** A hole the shape pattern of a quoted.Matcher.unapply, representing a splice */ + def patternHole(splice: Tree)(implicit ctx: Context): Tree = + ref(defn.InternalQuoted_patternHoleR).appliedToType(splice.tpe).withSpan(splice.span) def givenReflection(implicit ctx: Context): Tree = Literal(Constant(null)) // FIXME: fill in diff --git a/library/src-bootstrapped/scala/internal/Quoted.scala b/library/src-bootstrapped/scala/internal/Quoted.scala index b3d3f41cec9e..4e6122e7006d 100644 --- a/library/src-bootstrapped/scala/internal/Quoted.scala +++ b/library/src-bootstrapped/scala/internal/Quoted.scala @@ -16,4 +16,7 @@ object Quoted { def typeQuote[T <: AnyKind]: Type[T] = throw new Error("Internal error: this method call should have been replaced by the compiler") + /** A splice in a quoted pattern is desugared by the compiler into a call to this method */ + def patternHole[T]: T = + throw new Error("Internal error: this method call should have been replaced by the compiler") } diff --git a/tests/pos/quotedPatterns.scala b/tests/pos/quotedPatterns.scala index ef340a02972e..afc8e3a9d4cc 100644 --- a/tests/pos/quotedPatterns.scala +++ b/tests/pos/quotedPatterns.scala @@ -4,8 +4,10 @@ object Test { def f(x: Int) = x - x match { - case '{1 + 2} => 0 - case '{f($x)} => x + val res: quoted.Expr[Int] = x match { + case '{1 + 2} => '{0} + case '{f($y)} => y + //case '{ 1 + ($y: Int)} => y // currently gives an unreachable case error + case _ => '{1} } } \ No newline at end of file From 21b1aaad3620d3e878ff0b5e8dcf084172080885 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Mon, 1 Apr 2019 10:57:56 +0200 Subject: [PATCH 07/12] Always generate a tuple in Desugar.smallTuple Previously, the case where arity = 1 was treated specially. --- compiler/src/dotty/tools/dotc/ast/Desugar.scala | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/ast/Desugar.scala b/compiler/src/dotty/tools/dotc/ast/Desugar.scala index 449714c6b6d6..243e4b789ba2 100644 --- a/compiler/src/dotty/tools/dotc/ast/Desugar.scala +++ b/compiler/src/dotty/tools/dotc/ast/Desugar.scala @@ -1013,8 +1013,7 @@ object desugar { val arity = ts.length assert(arity <= Definitions.MaxTupleArity) def tupleTypeRef = defn.TupleType(arity) - if (arity == 1) ts.head - else if (arity == 0) + if (arity == 0) if (ctx.mode is Mode.Type) TypeTree(defn.UnitType) else unitLiteral else if (ctx.mode is Mode.Type) AppliedTypeTree(ref(tupleTypeRef), ts) else Apply(ref(tupleTypeRef.classSymbol.companionModule.termRef), ts) From c96d0932109e80cea3bb78e0356b5225819460f7 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Mon, 1 Apr 2019 10:58:51 +0200 Subject: [PATCH 08/12] Improve treatment of tuples --- .../src/dotty/tools/dotc/core/Definitions.scala | 9 ++++++--- compiler/src/dotty/tools/dotc/core/TypeOps.scala | 2 +- .../tools/dotc/printing/RefinedPrinter.scala | 2 +- .../dotty/tools/dotc/transform/TypeUtils.scala | 2 +- .../src/dotty/tools/dotc/typer/Deriving.scala | 4 ++-- compiler/src/dotty/tools/dotc/typer/Typer.scala | 16 +++++++++------- tests/pos/quotedPatterns.scala | 8 +++++++- 7 files changed, 27 insertions(+), 16 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/Definitions.scala b/compiler/src/dotty/tools/dotc/core/Definitions.scala index 014561661221..5c1c678dc02c 100644 --- a/compiler/src/dotty/tools/dotc/core/Definitions.scala +++ b/compiler/src/dotty/tools/dotc/core/Definitions.scala @@ -1170,7 +1170,9 @@ class Definitions { } def tupleType(elems: List[Type]): Type = { - TupleType(elems.size).appliedTo(elems) + val arity = elems.length + if (arity <= MaxTupleArity && TupleType(arity) != null) TupleType(arity).appliedTo(elems) + else TypeOps.nestedPairs(elems) } def isProductSubType(tp: Type)(implicit ctx: Context): Boolean = @@ -1263,8 +1265,9 @@ class Definitions { def adjustForTuple(cls: ClassSymbol, tparams: List[TypeSymbol], parents: List[Type]): List[Type] = { def syntheticParent(tparams: List[TypeSymbol]): Type = if (tparams.isEmpty) TupleTypeRef - else (tparams :\ (UnitType: Type)) ((tparam, tail) => PairType.appliedTo(tparam.typeRef, tail)) - if (isTupleClass(cls) || cls == UnitClass) parents :+ syntheticParent(tparams) else parents + else TypeOps.nestedPairs(tparams.map(_.typeRef)) + if (isTupleClass(cls) || cls == UnitClass) parents :+ syntheticParent(tparams) + else parents } // ----- primitive value class machinery ------------------------------------------ diff --git a/compiler/src/dotty/tools/dotc/core/TypeOps.scala b/compiler/src/dotty/tools/dotc/core/TypeOps.scala index b1dd4812a63b..250a7fdf7f58 100644 --- a/compiler/src/dotty/tools/dotc/core/TypeOps.scala +++ b/compiler/src/dotty/tools/dotc/core/TypeOps.scala @@ -570,6 +570,6 @@ object TypeOps { // TODO: Move other typeops here. It's a bit weird that they are a part of `ctx` - def tupleOf(ts: List[Type])(implicit ctx: Context): Type = + def nestedPairs(ts: List[Type])(implicit ctx: Context): Type = (ts :\ (defn.UnitType: Type))(defn.PairType.appliedTo(_, _)) } diff --git a/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala b/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala index 337ece1c59e3..92033c49c9dd 100644 --- a/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala +++ b/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala @@ -179,7 +179,7 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) { val cls = tycon.typeSymbol if (tycon.isRepeatedParam) return toTextLocal(args.head) ~ "*" if (defn.isFunctionClass(cls)) return toTextFunction(args, cls.name.isImplicitFunction, cls.name.isErasedFunction) - if (tp.tupleArity >= 2) return toTextTuple(tp.tupleElementTypes) + if (tp.tupleArity >= 2 && !ctx.settings.YprintDebug.value) return toTextTuple(tp.tupleElementTypes) if (isInfixType(tp)) { val l :: r :: Nil = args val opName = tyconName(tycon) diff --git a/compiler/src/dotty/tools/dotc/transform/TypeUtils.scala b/compiler/src/dotty/tools/dotc/transform/TypeUtils.scala index 509130df40e2..a0adbfe7ba42 100644 --- a/compiler/src/dotty/tools/dotc/transform/TypeUtils.scala +++ b/compiler/src/dotty/tools/dotc/transform/TypeUtils.scala @@ -50,6 +50,6 @@ object TypeUtils { /** The `*:` equivalent of an instance of a Tuple class */ def toNestedPairs(implicit ctx: Context): Type = - TypeOps.tupleOf(tupleElementTypes) + TypeOps.nestedPairs(tupleElementTypes) } } diff --git a/compiler/src/dotty/tools/dotc/typer/Deriving.scala b/compiler/src/dotty/tools/dotc/typer/Deriving.scala index 0dea4ebcba49..79e2c9c20e41 100644 --- a/compiler/src/dotty/tools/dotc/typer/Deriving.scala +++ b/compiler/src/dotty/tools/dotc/typer/Deriving.scala @@ -78,14 +78,14 @@ trait Deriving { this: Typer => case _ => (sym.termRef, Nil) } - val elemShape = TypeOps.tupleOf(elems) + val elemShape = TypeOps.nestedPairs(elems) defn.ShapeCaseType.appliedTo(constr, elemShape) } /** The shape of `cls` if `cls` is sealed */ private def sealedShape: Type = { val cases = children.map(caseShape).filter(_.exists) - val casesShape = TypeOps.tupleOf(cases) + val casesShape = TypeOps.nestedPairs(cases) defn.ShapeCasesType.appliedTo(casesShape) } diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala index ea9a470c3f06..048bb2651afb 100644 --- a/compiler/src/dotty/tools/dotc/typer/Typer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala @@ -1919,7 +1919,7 @@ class Typer extends Namer else { val elemTpes = (elems, pts).zipped.map((elem, pt) => ctx.typeComparer.widenInferred(elem.tpe, pt)) - val resTpe = TypeOps.tupleOf(elemTpes) + val resTpe = TypeOps.nestedPairs(elemTpes) app1.cast(resTpe) } } @@ -1942,13 +1942,15 @@ class Typer extends Namer val quotedPt = if (exprPt.exists) exprPt.argTypesHi.head else defn.AnyType val quoted1 = typedExpr(quoted, quotedPt)(quoteContext.addMode(Mode.QuotedPattern)) val (shape, splices) = splitQuotePattern(quoted1) - val splicePat = typed(untpd.Tuple(splices.map(untpd.TypedSplice(_))).withSpan(quoted.span)) - val patType = TypeOps.tupleOf(splices.tpes.map(_.widen)) + val patType = defn.tupleType(splices.tpes.map(_.widen)) + val splicePat = typed(untpd.Tuple(splices.map(untpd.TypedSplice(_))).withSpan(quoted.span), patType) UnApply( - ref(defn.QuotedMatcher_unapplyR).appliedToType(patType), - ref(defn.InternalQuoted_exprQuoteR).appliedToType(shape.tpe).appliedTo(shape) :: givenReflection :: Nil, - splicePat :: Nil, - pt) + fun = ref(defn.QuotedMatcher_unapplyR).appliedToType(patType), + implicits = + ref(defn.InternalQuoted_exprQuoteR).appliedToType(shape.tpe).appliedTo(shape) :: + givenReflection :: Nil, + patterns = splicePat :: Nil, + proto = pt) } else typedApply(untpd.Apply(untpd.ref(defn.InternalQuoted_exprQuoteR), quoted), pt)(quoteContext).withSpan(tree.span) diff --git a/tests/pos/quotedPatterns.scala b/tests/pos/quotedPatterns.scala index afc8e3a9d4cc..c99672fa345d 100644 --- a/tests/pos/quotedPatterns.scala +++ b/tests/pos/quotedPatterns.scala @@ -3,11 +3,17 @@ object Test { val x = '{1 + 2} def f(x: Int) = x + def g(x: Int, y: Int) = x * y val res: quoted.Expr[Int] = x match { case '{1 + 2} => '{0} case '{f($y)} => y - //case '{ 1 + ($y: Int)} => y // currently gives an unreachable case error + case '{g($y, $z)} => '{$y * $z} + case '{ 1 + ($y: Int)} => y + // currently gives an unreachable case warning + // but only when used in conjunction with the others. + // I believe this is because implicit arguments are not taken + // into account when checking whether we have already seen an `unapply` before. case _ => '{1} } } \ No newline at end of file From 3cef70115eff48b7d058fa482a730860246ac103 Mon Sep 17 00:00:00 2001 From: Nicolas Stucki Date: Mon, 1 Apr 2019 17:48:25 +0200 Subject: [PATCH 09/12] Fix pattern decompiler Now we can have patterns that do not have a full tree (i.e. just an Ident to the `unapply`) --- library/src/scala/tasty/reflect/Printers.scala | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/library/src/scala/tasty/reflect/Printers.scala b/library/src/scala/tasty/reflect/Printers.scala index b96d82f5d92c..1680f8f5335c 100644 --- a/library/src/scala/tasty/reflect/Printers.scala +++ b/library/src/scala/tasty/reflect/Printers.scala @@ -1310,10 +1310,17 @@ trait Printers printPattern(pattern) case Pattern.Unapply(fun, implicits, patterns) => - fun match { - case Select(extractor, "unapply" | "unapplySeq") => printTree(extractor) - case TypeApply(Select(extractor, "unapply" | "unapplySeq"), _) => printTree(extractor) - case _ => throw new MatchError(fun.show) + val fun2 = fun match { + case TypeApply(fun2, _) => fun2 + case _ => fun + } + fun2 match { + case Select(extractor, "unapply" | "unapplySeq") => + printTree(extractor) + case Ident("unapply" | "unapplySeq") => + this += fun.symbol.owner.fullName.stripSuffix("$") + case _ => + throw new MatchError(fun.show) } inParens(printPatterns(patterns, ", ")) From 7bae5750b7a97bf9af49fbc83f3e8d343e49b998 Mon Sep 17 00:00:00 2001 From: Nicolas Stucki Date: Mon, 1 Apr 2019 21:01:14 +0200 Subject: [PATCH 10/12] Check level in pattern match --- compiler/src/dotty/tools/dotc/typer/Typer.scala | 4 ++-- tests/neg/quotedPatterns.scala | 12 ++++++++++++ 2 files changed, 14 insertions(+), 2 deletions(-) create mode 100644 tests/neg/quotedPatterns.scala diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala index 048bb2651afb..38ce22cedf8a 100644 --- a/compiler/src/dotty/tools/dotc/typer/Typer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala @@ -1937,7 +1937,7 @@ class Typer extends Namer case quoted if quoted.isType => typedTypeApply(untpd.TypeApply(untpd.ref(defn.InternalQuoted_typeQuoteR), quoted :: Nil), pt)(quoteContext).withSpan(tree.span) case quoted => - if (ctx.mode.is(Mode.Pattern)) { + if (ctx.mode.is(Mode.Pattern) && level == 0) { val exprPt = pt.baseType(defn.QuotedExprClass) val quotedPt = if (exprPt.exists) exprPt.argTypesHi.head else defn.AnyType val quoted1 = typedExpr(quoted, quotedPt)(quoteContext.addMode(Mode.QuotedPattern)) @@ -1989,7 +1989,7 @@ class Typer extends Namer ctx.warning("Canceled quote directly inside a splice. ${ '{ XYZ } } is equivalent to XYZ.", tree.sourcePos) typed(innerExpr, pt) case expr => - if (ctx.mode.is(Mode.QuotedPattern)) { + if (ctx.mode.is(Mode.QuotedPattern) && level == 1) { fullyDefinedType(pt, "quoted pattern selector", tree.span) val pat = typedPattern(expr, defn.QuotedExprType.appliedTo(pt))( spliceContext.retractMode(Mode.QuotedPattern)) diff --git a/tests/neg/quotedPatterns.scala b/tests/neg/quotedPatterns.scala new file mode 100644 index 000000000000..85f351c1d274 --- /dev/null +++ b/tests/neg/quotedPatterns.scala @@ -0,0 +1,12 @@ +object Test { + + val x = '{1 + 2} + + def f(x: Int) = x + def g(x: Int, y: Int) = x * y + + x match { + case '{ val a = '{ println($y) }; 0 } => ??? // error: Not found: y + case _ => + } +} \ No newline at end of file From 124a491850b9d44da736701d59305890b212e7f0 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Tue, 2 Apr 2019 11:26:20 +0200 Subject: [PATCH 11/12] Infer implicit Reflection argument to Matcher.unapply --- compiler/src/dotty/tools/dotc/typer/Typer.scala | 5 +++-- tests/neg/quotedPatterns.scala | 2 +- tests/pos/quotedPatterns.scala | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala index 38ce22cedf8a..fa07d3397081 100644 --- a/compiler/src/dotty/tools/dotc/typer/Typer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala @@ -1948,7 +1948,7 @@ class Typer extends Namer fun = ref(defn.QuotedMatcher_unapplyR).appliedToType(patType), implicits = ref(defn.InternalQuoted_exprQuoteR).appliedToType(shape.tpe).appliedTo(shape) :: - givenReflection :: Nil, + givenReflection(tree.span) :: Nil, patterns = splicePat :: Nil, proto = pt) } @@ -1979,7 +1979,8 @@ class Typer extends Namer def patternHole(splice: Tree)(implicit ctx: Context): Tree = ref(defn.InternalQuoted_patternHoleR).appliedToType(splice.tpe).withSpan(splice.span) - def givenReflection(implicit ctx: Context): Tree = Literal(Constant(null)) // FIXME: fill in + def givenReflection(span: Span)(implicit ctx: Context): Tree = + implicitArgTree(defn.TastyReflectionType, span) /** Translate `${ t: Expr[T] }` into expression `t.splice` while tracking the quotation level in the context */ def typedSplice(tree: untpd.Splice, pt: Type)(implicit ctx: Context): Tree = track("typedSplice") { diff --git a/tests/neg/quotedPatterns.scala b/tests/neg/quotedPatterns.scala index 85f351c1d274..cd067eb74cab 100644 --- a/tests/neg/quotedPatterns.scala +++ b/tests/neg/quotedPatterns.scala @@ -5,7 +5,7 @@ object Test { def f(x: Int) = x def g(x: Int, y: Int) = x * y - x match { + def test given tasty.Reflection = x match { case '{ val a = '{ println($y) }; 0 } => ??? // error: Not found: y case _ => } diff --git a/tests/pos/quotedPatterns.scala b/tests/pos/quotedPatterns.scala index c99672fa345d..887104184a27 100644 --- a/tests/pos/quotedPatterns.scala +++ b/tests/pos/quotedPatterns.scala @@ -5,7 +5,7 @@ object Test { def f(x: Int) = x def g(x: Int, y: Int) = x * y - val res: quoted.Expr[Int] = x match { + def res given tasty.Reflection: quoted.Expr[Int] = x match { case '{1 + 2} => '{0} case '{f($y)} => y case '{g($y, $z)} => '{$y * $z} From 1a9ec2357ec78e00efe135114736f75d561a0ba6 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Tue, 2 Apr 2019 11:30:51 +0200 Subject: [PATCH 12/12] Simplification: Inline givenReflection --- compiler/src/dotty/tools/dotc/typer/Typer.scala | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala index fa07d3397081..1c81ef0ec665 100644 --- a/compiler/src/dotty/tools/dotc/typer/Typer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala @@ -1948,7 +1948,7 @@ class Typer extends Namer fun = ref(defn.QuotedMatcher_unapplyR).appliedToType(patType), implicits = ref(defn.InternalQuoted_exprQuoteR).appliedToType(shape.tpe).appliedTo(shape) :: - givenReflection(tree.span) :: Nil, + implicitArgTree(defn.TastyReflectionType, tree.span) :: Nil, patterns = splicePat :: Nil, proto = pt) } @@ -1979,9 +1979,6 @@ class Typer extends Namer def patternHole(splice: Tree)(implicit ctx: Context): Tree = ref(defn.InternalQuoted_patternHoleR).appliedToType(splice.tpe).withSpan(splice.span) - def givenReflection(span: Span)(implicit ctx: Context): Tree = - implicitArgTree(defn.TastyReflectionType, span) - /** Translate `${ t: Expr[T] }` into expression `t.splice` while tracking the quotation level in the context */ def typedSplice(tree: untpd.Splice, pt: Type)(implicit ctx: Context): Tree = track("typedSplice") { checkSpliceOutsideQuote(tree)