From d91f66ff783682e473909299f3775db07b784101 Mon Sep 17 00:00:00 2001 From: odersky Date: Mon, 23 Jan 2023 14:51:54 +0100 Subject: [PATCH] Don't generate a Select for a TermRef with NoPrefix In TreeTypeMap, don't generate a Select node if the new type of the tree is a TermRef with NoPrefix. Generate an Ident node instead. Fixes #16740 --- .../dotty/tools/dotc/ast/TreeTypeMap.scala | 40 ++++++++++++------- compiler/src/dotty/tools/dotc/ast/tpd.scala | 4 ++ .../dotty/tools/dotc/transform/Erasure.scala | 2 +- tests/pos/i16740.scala | 8 ++++ 4 files changed, 38 insertions(+), 16 deletions(-) create mode 100644 tests/pos/i16740.scala diff --git a/compiler/src/dotty/tools/dotc/ast/TreeTypeMap.scala b/compiler/src/dotty/tools/dotc/ast/TreeTypeMap.scala index f5bf55802adf..faeafae97f5e 100644 --- a/compiler/src/dotty/tools/dotc/ast/TreeTypeMap.scala +++ b/compiler/src/dotty/tools/dotc/ast/TreeTypeMap.scala @@ -43,7 +43,7 @@ class TreeTypeMap( def copy( typeMap: Type => Type, - treeMap: tpd.Tree => tpd.Tree, + treeMap: Tree => Tree, oldOwners: List[Symbol], newOwners: List[Symbol], substFrom: List[Symbol], @@ -85,13 +85,13 @@ class TreeTypeMap( updateDecls(prevStats.tail, newStats.tail) } - def transformInlined(tree: tpd.Inlined)(using Context): tpd.Tree = + def transformInlined(tree: Inlined)(using Context): Tree = val Inlined(call, bindings, expanded) = tree val (tmap1, bindings1) = transformDefs(bindings) val expanded1 = tmap1.transform(expanded) cpy.Inlined(tree)(call, bindings1, expanded1) - override def transform(tree: tpd.Tree)(using Context): tpd.Tree = treeMap(tree) match { + override def transform(tree: Tree)(using Context): Tree = treeMap(tree) match { case impl @ Template(constr, _, self, _) => val tmap = withMappedSyms(localSyms(impl :: self :: Nil)) cpy.Template(impl)( @@ -103,8 +103,24 @@ class TreeTypeMap( ).withType(tmap.mapType(impl.tpe)) case tree1 => tree1.withType(mapType(tree1.tpe)) match { - case id: Ident if tpd.needsSelect(id.tpe) => - ref(id.tpe.asInstanceOf[TermRef]).withSpan(id.span) + case id: Ident => + if needsSelect(id.tpe) then + ref(id.tpe.asInstanceOf[TermRef]).withSpan(id.span) + else + super.transform(id) + case sel: Select => + if needsIdent(sel.tpe) then + ref(sel.tpe.asInstanceOf[TermRef]).withSpan(sel.span) + else + super.transform(sel) + case app: Apply => + super.transform(app) + case blk @ Block(stats, expr) => + val (tmap1, stats1) = transformDefs(stats) + val expr1 = tmap1.transform(expr) + cpy.Block(blk)(stats1, expr1) + case lit @ Literal(Constant(tpe: Type)) => + cpy.Literal(lit)(Constant(mapType(tpe))) case ddef @ DefDef(name, paramss, tpt, _) => val (tmap1, paramss1) = transformAllParamss(paramss) val res = cpy.DefDef(ddef)(name, paramss1, tmap1.transform(tpt), tmap1.transform(ddef.rhs)) @@ -117,10 +133,6 @@ class TreeTypeMap( case tdef @ LambdaTypeTree(tparams, body) => val (tmap1, tparams1) = transformDefs(tparams) cpy.LambdaTypeTree(tdef)(tparams1, tmap1.transform(body)) - case blk @ Block(stats, expr) => - val (tmap1, stats1) = transformDefs(stats) - val expr1 = tmap1.transform(expr) - cpy.Block(blk)(stats1, expr1) case inlined: Inlined => transformInlined(inlined) case cdef @ CaseDef(pat, guard, rhs) => @@ -139,18 +151,16 @@ class TreeTypeMap( val content1 = transform(content) val tpt1 = transform(tpt) cpy.Hole(tree)(args = args1, content = content1, tpt = tpt1) - case lit @ Literal(Constant(tpe: Type)) => - cpy.Literal(lit)(Constant(mapType(tpe))) case tree1 => super.transform(tree1) } } - override def transformStats(trees: List[tpd.Tree], exprOwner: Symbol)(using Context): List[Tree] = + override def transformStats(trees: List[Tree], exprOwner: Symbol)(using Context): List[Tree] = transformDefs(trees)._2 - def transformDefs[TT <: tpd.Tree](trees: List[TT])(using Context): (TreeTypeMap, List[TT]) = { - val tmap = withMappedSyms(tpd.localSyms(trees)) + def transformDefs[TT <: Tree](trees: List[TT])(using Context): (TreeTypeMap, List[TT]) = { + val tmap = withMappedSyms(localSyms(trees)) (tmap, tmap.transformSub(trees)) } @@ -165,7 +175,7 @@ class TreeTypeMap( case nil => (this, paramss) - def apply[ThisTree <: tpd.Tree](tree: ThisTree): ThisTree = transform(tree).asInstanceOf[ThisTree] + def apply[ThisTree <: Tree](tree: ThisTree): ThisTree = transform(tree).asInstanceOf[ThisTree] def apply(annot: Annotation): Annotation = annot.derivedAnnotation(apply(annot.tree)) diff --git a/compiler/src/dotty/tools/dotc/ast/tpd.scala b/compiler/src/dotty/tools/dotc/ast/tpd.scala index dd1e46c62223..1a202ece1e66 100644 --- a/compiler/src/dotty/tools/dotc/ast/tpd.scala +++ b/compiler/src/dotty/tools/dotc/ast/tpd.scala @@ -414,6 +414,10 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo { case _ => false } + def needsIdent(tp: Type)(using Context): Boolean = tp match + case tp: TermRef => tp.prefix eq NoPrefix + case _ => false + /** A tree representing the same reference as the given type */ def ref(tp: NamedType, needLoad: Boolean = true)(using Context): Tree = if (tp.isType) TypeTree(tp) diff --git a/compiler/src/dotty/tools/dotc/transform/Erasure.scala b/compiler/src/dotty/tools/dotc/transform/Erasure.scala index 129964557995..60affae38ad5 100644 --- a/compiler/src/dotty/tools/dotc/transform/Erasure.scala +++ b/compiler/src/dotty/tools/dotc/transform/Erasure.scala @@ -774,7 +774,7 @@ object Erasure { select(qual1, sym) else val castTarget = // Avoid inaccessible cast targets, see i8661 - if isJvmAccessible(sym.owner) + if isJvmAccessible(sym.owner) && sym.owner.isType then sym.owner.typeRef else diff --git a/tests/pos/i16740.scala b/tests/pos/i16740.scala new file mode 100644 index 000000000000..398518ee77ef --- /dev/null +++ b/tests/pos/i16740.scala @@ -0,0 +1,8 @@ +class Enclosing: + object Tags: + opaque type Ref[T, S <: String & Singleton] = S + inline def require[T, S <: String & Singleton]: Ref[T, S] = ??? + import Tags.* + + val t1 = require[Int, "t1"] + val t2 = require[Double, "t2"]