diff --git a/compiler/src/dotty/tools/dotc/ast/TreeInfo.scala b/compiler/src/dotty/tools/dotc/ast/TreeInfo.scala index f6622eedd04b..d1dbd7f54266 100644 --- a/compiler/src/dotty/tools/dotc/ast/TreeInfo.scala +++ b/compiler/src/dotty/tools/dotc/ast/TreeInfo.scala @@ -388,7 +388,7 @@ trait TypedTreeInfo extends TreeInfo[Type] { self: Trees.Instance[Type] => case New(_) | Closure(_, _, _) => Pure case TypeApply(fn, _) => - if (fn.symbol.is(Erased)) Pure else exprPurity(fn) + if (fn.symbol.is(Erased) || fn.symbol == defn.InternalQuoted_typeQuote) Pure else exprPurity(fn) case Apply(fn, args) => def isKnownPureOp(sym: Symbol) = sym.owner.isPrimitiveValueClass || sym.owner == defn.StringClass diff --git a/compiler/src/dotty/tools/dotc/transform/PCPCheckAndHeal.scala b/compiler/src/dotty/tools/dotc/transform/PCPCheckAndHeal.scala index 1da497b19109..6eee079dc4f2 100644 --- a/compiler/src/dotty/tools/dotc/transform/PCPCheckAndHeal.scala +++ b/compiler/src/dotty/tools/dotc/transform/PCPCheckAndHeal.scala @@ -202,13 +202,17 @@ class PCPCheckAndHeal(@constructorOnly ictx: Context) extends TreeMapWithStages( val reqType = defn.QuotedTypeType.appliedTo(tp) val tag = ctx.typer.inferImplicitArg(reqType, pos.span) tag.tpe match { - case fail: SearchFailureType => + case _: TermRef => + Some(tag.select(tpnme.splice)) + case _: SearchFailureType => levelError(i""" | | The access would be accepted with the right type tag, but | ${ctx.typer.missingArgMsg(tag, reqType, "")}""") case _ => - Some(tag.select(tpnme.splice)) + levelError(i""" + | + | The access would be accepted with an implict $reqType""") } } case _ => diff --git a/compiler/src/dotty/tools/dotc/transform/Staging.scala b/compiler/src/dotty/tools/dotc/transform/Staging.scala index 6d839ba2160a..d55a26b33b5a 100644 --- a/compiler/src/dotty/tools/dotc/transform/Staging.scala +++ b/compiler/src/dotty/tools/dotc/transform/Staging.scala @@ -61,6 +61,15 @@ class Staging extends MacroTransform { checker.transform(tree) case _ => } + + tree.tpe match { + case tpe @ TypeRef(prefix, _) if tpe.typeSymbol eq defn.QuotedType_splice => + // Type splices must have a know term ref, usually to an implicit argument + // This is mostly intended to catch `quoted.Type[T]#splice` types which should just be `T` + assert(prefix.isInstanceOf[TermRef] || prefix.isInstanceOf[ThisType], prefix) + case _ => + // OK + } } } diff --git a/compiler/src/dotty/tools/dotc/typer/Implicits.scala b/compiler/src/dotty/tools/dotc/typer/Implicits.scala index 7a70fede9328..b09b221521d5 100644 --- a/compiler/src/dotty/tools/dotc/typer/Implicits.scala +++ b/compiler/src/dotty/tools/dotc/typer/Implicits.scala @@ -674,6 +674,9 @@ trait Implicits { self: Typer => EmptyTree } + /** Synthesize the tree for `'[T]` for an implicit `scala.quoted.Type[T]`. + * `T` is deeply dealiassed to avoid references to local type aliases. + */ lazy val synthesizedTypeTag: SpecialHandler = (formal: Type, span: Span) => implicit (ctx: Context) => { def quotedType(t: Type) = { @@ -682,26 +685,11 @@ trait Implicits { self: Typer => ref(defn.InternalQuoted_typeQuote).appliedToType(t) } formal.argInfos match { - case arg :: Nil if !arg.typeSymbol.is(Param) => - object bindFreeVars extends TypeMap { - var ok = true - def apply(t: Type) = t match { - case t @ TypeRef(NoPrefix, _) => - inferImplicit(defn.QuotedTypeType.appliedTo(t), EmptyTree, span) match { - case SearchSuccess(tag, _, _) if tag.tpe.isStable => - tag.tpe.select(defn.QuotedType_splice) - case _ => - ok = false - t - } - case _ => t - } + case arg :: Nil => + val deepDealias = new TypeMap { + def apply(tp: Type): Type = mapOver(tp.dealias) } - val tag = bindFreeVars(arg) - if (bindFreeVars.ok) quotedType(tag) - else EmptyTree - case arg :: Nil if ctx.inInlineMethod => - quotedType(arg) + quotedType(deepDealias(arg)) case _ => EmptyTree } diff --git a/tests/neg/quote-0.scala b/tests/neg/quote-0.scala index 5f4299d10682..69909b715eda 100644 --- a/tests/neg/quote-0.scala +++ b/tests/neg/quote-0.scala @@ -14,12 +14,4 @@ class Test { '{(y: Expr[Int]) => $y } // error: wrong staging level - def f[T](t: Type[T], x: Expr[T]) = '{ - val z2 = $x // error // error: wrong staging level - } - - def g[T](implicit t: Type[T], x: Expr[T]) = '{ - val z2 = $x // ok - } - } diff --git a/tests/neg/quote-1.scala b/tests/neg/quote-1.scala new file mode 100644 index 000000000000..fec60fa716e5 --- /dev/null +++ b/tests/neg/quote-1.scala @@ -0,0 +1,13 @@ +import scala.quoted._ + +class Test { + + def f[T](t: Type[T], x: Expr[T]) = '{ + val z2 = $x // error // error: wrong staging level + } + + def g[T](implicit t: Type[T], x: Expr[T]) = '{ + val z2 = $x // ok + } + +} diff --git a/tests/pos/i6588.scala b/tests/pos/i6588.scala new file mode 100644 index 000000000000..c9ad60584be2 --- /dev/null +++ b/tests/pos/i6588.scala @@ -0,0 +1,27 @@ +import scala.quoted._ + +inline def foo[T:Type]: Int = 10 + +def main = { + type S = Int + foo[S] + foo[Int] + + type T = Int => Int + foo[T] + foo[Int => Int] + + type U = List[Int] + foo[U] + foo[List[Int]] + + type N = List + foo[N] + foo[List] + + type V = List[S] + foo[V] + + type B = V => T + foo[B] +} diff --git a/tests/run-with-compiler/i4350.check b/tests/run-with-compiler/i4350.check index e670af3da233..5072214a8280 100644 --- a/tests/run-with-compiler/i4350.check +++ b/tests/run-with-compiler/i4350.check @@ -1,2 +1,2 @@ (null: scala.Any).asInstanceOf[java.lang.Object] -(null: scala.Any).asInstanceOf[scala.Predef.String] +(null: scala.Any).asInstanceOf[java.lang.String]