Skip to content
Merged
54 changes: 29 additions & 25 deletions compiler/src/dotty/tools/dotc/typer/QuotesAndSplices.scala
Original file line number Diff line number Diff line change
Expand Up @@ -97,26 +97,25 @@ trait QuotesAndSplices {
ctx.warning("Canceled quote directly inside a splice. ${ '[ XYZ ] } is equivalent to XYZ.", tree.sourcePos)
case _ =>
}

if (ctx.mode.is(Mode.QuotedPattern) && level == 1)
if (isFullyDefined(pt, ForceDegree.all)) {
ctx.error(i"Spliced type pattern must not be fully defined. Consider using $pt directly", tree.expr.sourcePos)
tree.withType(UnspecifiedErrorType)
}
else {
def spliceOwner(ctx: Context): Symbol =
if (ctx.mode.is(Mode.QuotedPattern)) spliceOwner(ctx.outer) else ctx.owner
val name = tree.expr match {
case Ident(name) => ("$" + name).toTypeName
case expr =>
ctx.error("expected a name binding", expr.sourcePos)
"$error".toTypeName
}
val typeSym = ctx.newSymbol(spliceOwner(ctx), name, EmptyFlags, TypeBounds.empty, NoSymbol, tree.expr.span)
typeSym.addAnnotation(Annotation(New(ref(defn.InternalQuoted_patternBindHoleAnnot.typeRef)).withSpan(tree.expr.span)))
val pat = typedPattern(tree.expr, defn.QuotedTypeClass.typeRef.appliedTo(typeSym.typeRef))(
spliceContext.retractMode(Mode.QuotedPattern).withOwner(spliceOwner(ctx)))
pat.select(tpnme.splice)
def spliceOwner(ctx: Context): Symbol =
if (ctx.mode.is(Mode.QuotedPattern)) spliceOwner(ctx.outer) else ctx.owner
val name = tree.expr match {
case Ident(name) => ("$" + name).toTypeName
case expr =>
ctx.error("expected a name binding", expr.sourcePos)
"$error".toTypeName
}

val typeSymInfo = pt match
case pt: TypeBounds => pt
case _ => TypeBounds.empty
val typeSym = ctx.newSymbol(spliceOwner(ctx), name, EmptyFlags, typeSymInfo, NoSymbol, tree.expr.span)
typeSym.addAnnotation(Annotation(New(ref(defn.InternalQuoted_patternBindHoleAnnot.typeRef)).withSpan(tree.expr.span)))
val pat = typedPattern(tree.expr, defn.QuotedTypeClass.typeRef.appliedTo(typeSym.typeRef))(
spliceContext.retractMode(Mode.QuotedPattern).withOwner(spliceOwner(ctx)))
pat.select(tpnme.splice)
else
typedSelect(untpd.Select(tree.expr, tpnme.splice), pt)(spliceContext).withSpan(tree.span)
}
Expand Down Expand Up @@ -191,11 +190,13 @@ trait QuotesAndSplices {
patBuf += pat1
}
case Select(pat, _) if tree.symbol == defn.QuotedType_splice =>
val sym = tree.tpe.dealias.typeSymbol.asType
val tdef = TypeDef(sym).withSpan(sym.span)
freshTypeBindingsBuff += transformTypeBindingTypeDef(tdef, freshTypePatBuf)
TypeTree(tree.tpe.dealias).withSpan(tree.span)

val sym = tree.tpe.dealias.typeSymbol
if sym.exists then
val tdef = TypeDef(sym.asType).withSpan(sym.span)
freshTypeBindingsBuff += transformTypeBindingTypeDef(tdef, freshTypePatBuf)
TypeTree(tree.tpe.dealias).withSpan(tree.span)
else
tree
case ddef: ValOrDefDef =>
if (ddef.symbol.hasAnnotation(defn.InternalQuoted_patternBindHoleAnnot)) {
val bindingType = ddef.symbol.info match {
Expand Down Expand Up @@ -317,13 +318,16 @@ trait QuotesAndSplices {
ctx.error(missingArgMsg(qctx, defn.QuoteContextClass.typeRef, ""), ctx.source.atSpan(tree.span))

val quoted = tree.quoted
val exprPt = pt.baseType(defn.QuotedExprClass)
val exprPt = pt.baseType(if quoted.isType then defn.QuotedTypeClass else defn.QuotedExprClass)
val quotedPt = exprPt.argInfos.headOption match {
case Some(argPt: ValueType) => argPt // excludes TypeBounds
case _ => defn.AnyType
}
val quoted0 = desugar.quotedPattern(quoted, untpd.TypedSplice(TypeTree(quotedPt)))
val quoted1 = typedExpr(quoted0, WildcardType)(quoteContext.addMode(Mode.QuotedPattern))
val quoteCtx = quoteContext.addMode(Mode.QuotedPattern)
val quoted1 =
if quoted.isType then typedType(quoted0, WildcardType)(quoteCtx)
else typedExpr(quoted0, WildcardType)(quoteCtx)

val (typeBindings, shape, splices) = splitQuotePattern(quoted1)

Expand Down
8 changes: 5 additions & 3 deletions compiler/src/dotty/tools/dotc/typer/Typer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -1389,8 +1389,10 @@ class Typer extends Namer
def typedArg(arg: untpd.Tree, tparam: ParamInfo) = {
def tparamBounds = tparam.paramInfoAsSeenFrom(tpt1.tpe.appliedTo(tparams.map(_ => TypeBounds.empty)))
val (desugaredArg, argPt) =
if (ctx.mode is Mode.Pattern)
if ctx.mode.is(Mode.Pattern) then
(if (untpd.isVarPattern(arg)) desugar.patternVar(arg) else arg, tparamBounds)
else if ctx.mode.is(Mode.QuotedPattern) then
(arg, tparamBounds)
else
(arg, WildcardType)
if (tpt1.symbol.isClass)
Expand Down Expand Up @@ -2177,7 +2179,7 @@ class Typer extends Namer

/** Typecheck and adapt tree, returning a typed tree. Parameters as for `typedUnadapted` */
def typed(tree: untpd.Tree, pt: Type, locked: TypeVars)(implicit ctx: Context): Tree =
trace(i"typing $tree", typr, show = true) {
trace(i"typing $tree, pt = $pt", typr, show = true) {
record(s"typed $getClass")
record("typed total")
assertPositioned(tree)
Expand Down Expand Up @@ -3030,7 +3032,7 @@ class Typer extends Namer
tree.tpe.EtaExpand(tp.typeParamSymbols)
tree.withType(tp1)
}
if ((ctx.mode is Mode.Pattern) || tree1.tpe <:< pt) tree1
if (ctx.mode.is(Mode.Pattern) || ctx.mode.is(Mode.QuotedPattern) || tree1.tpe <:< pt) tree1
else err.typeMismatch(tree1, pt)
}

Expand Down
7 changes: 7 additions & 0 deletions tests/neg/i7264d.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import scala.quoted._
class Foo {
def f[T2: Type](e: Expr[T2])(given QuoteContext) = e match {
case '{ $x: *:[Int, Any] } => // error: Type argument Any does not conform to upper bound Tuple

}
}
7 changes: 7 additions & 0 deletions tests/pos/i7264.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import scala.quoted._
class Foo {
def f[T2](t: Type[T2])(given QuoteContext) = t match {
case '[ *:[Int, $t] ] =>
'[ *:[Int, $t] ]
}
}
7 changes: 7 additions & 0 deletions tests/pos/i7264b.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import scala.quoted._
class Foo {
def f[T2: Type](e: Expr[T2])(given QuoteContext) = e match {
case '{ $x: *:[Int, $t] } =>
'[ *:[Int, $t] ]
}
}
9 changes: 9 additions & 0 deletions tests/pos/i7264c.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import scala.quoted._
class Foo {
def f[T2: Type](e: Expr[T2])(given QuoteContext) = e match {
case '{ $x: $t0 } =>
t0 match
case '[ *:[Int, $t] ] =>
'[ *:[Int, $t] ]
}
}