From 226e809e84e505f1f06fc51c437b3146a9d0a1e1 Mon Sep 17 00:00:00 2001 From: Guillaume Martres Date: Wed, 10 Feb 2021 14:49:39 +0100 Subject: [PATCH] Recover the denotation of constant-folded selections With this change, the only term selections without a symbol after Typer and before Pickler come from polymorphic function calls or outer selects. This should be good enough to let us use SELECTin in all situations where overloads can appear as #11210 is attempting. --- compiler/src/dotty/tools/dotc/ast/Trees.scala | 9 ++++++++- .../dotty/tools/dotc/transform/TreeChecker.scala | 14 +++++++++++++- .../src/dotty/tools/dotc/typer/ConstFold.scala | 2 +- 3 files changed, 22 insertions(+), 3 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/ast/Trees.scala b/compiler/src/dotty/tools/dotc/ast/Trees.scala index 65c81ce42e13..23996ce14dfb 100644 --- a/compiler/src/dotty/tools/dotc/ast/Trees.scala +++ b/compiler/src/dotty/tools/dotc/ast/Trees.scala @@ -4,7 +4,7 @@ package ast import core._ import Types._, Names._, NameOps._, Flags._, util.Spans._, Contexts._, Constants._ -import typer.ProtoTypes +import typer.{ ConstFold, ProtoTypes } import SymDenotations._, Symbols._, Denotations._, StdNames._, Comments._ import language.higherKinds import collection.mutable.ListBuffer @@ -408,6 +408,13 @@ object Trees { case class Select[-T >: Untyped] private[ast] (qualifier: Tree[T], name: Name)(implicit @constructorOnly src: SourceFile) extends RefTree[T] { type ThisTree[-T >: Untyped] = Select[T] + + override def denot(using Context): Denotation = typeOpt match + case ConstantType(_) if ConstFold.foldedUnops.contains(name) => + // Recover the denotation of a constant-folded selection + qualifier.typeOpt.member(name).atSignature(Signature.NotAMethod, name) + case _ => + super.denot } class SelectWithSig[-T >: Untyped] private[ast] (qualifier: Tree[T], name: Name, val sig: Signature)(implicit @constructorOnly src: SourceFile) diff --git a/compiler/src/dotty/tools/dotc/transform/TreeChecker.scala b/compiler/src/dotty/tools/dotc/transform/TreeChecker.scala index 7eaad36b18a2..4ebe2cf41fad 100644 --- a/compiler/src/dotty/tools/dotc/transform/TreeChecker.scala +++ b/compiler/src/dotty/tools/dotc/transform/TreeChecker.scala @@ -380,6 +380,17 @@ class TreeChecker extends Phase with SymTransformer { override def typedSelect(tree: untpd.Select, pt: Type)(using Context): Tree = { assert(tree.isTerm || !ctx.isAfterTyper, tree.show + " at " + ctx.phase) val tpe = tree.typeOpt + + // Polymorphic apply methods stay structural until Erasure + val isPolyFunctionApply = (tree.name eq nme.apply) && (tree.qualifier.typeOpt <:< defn.PolyFunctionType) + // Outer selects are pickled specially so don't require a symbol + val isOuterSelect = tree.name.is(OuterSelectName) + val isPrimitiveArrayOp = ctx.erasedTypes && nme.isPrimitiveName(tree.name) + if !(tree.isType || isPolyFunctionApply || isOuterSelect || isPrimitiveArrayOp) then + val denot = tree.denot + assert(denot.exists, i"Selection $tree with type $tpe does not have a denotation") + assert(denot.symbol.exists, i"Denotation $denot of selection $tree with type $tpe does not have a symbol") + val sym = tree.symbol val symIsFixed = tpe match { case tpe: TermRef => ctx.erasedTypes || !tpe.isMemberRef @@ -387,7 +398,7 @@ class TreeChecker extends Phase with SymTransformer { } if (sym.exists && !sym.is(Private) && !symIsFixed && - !tree.name.is(OuterSelectName)) { // outer selects have effectively fixed symbols + !isOuterSelect) { // outer selects have effectively fixed symbols val qualTpe = tree.qualifier.typeOpt val member = if (sym.is(Private)) qualTpe.member(tree.name) @@ -403,6 +414,7 @@ class TreeChecker extends Phase with SymTransformer { |qualifier type : ${tree.qualifier.typeOpt} |tree type : ${tree.typeOpt} of class ${tree.typeOpt.getClass}""") } + checkNotRepeated(super.typedSelect(tree, pt)) } diff --git a/compiler/src/dotty/tools/dotc/typer/ConstFold.scala b/compiler/src/dotty/tools/dotc/typer/ConstFold.scala index 0bf1e4a076ea..4633c187912f 100644 --- a/compiler/src/dotty/tools/dotc/typer/ConstFold.scala +++ b/compiler/src/dotty/tools/dotc/typer/ConstFold.scala @@ -23,7 +23,7 @@ object ConstFold: nme.LT, nme.GT, nme.LE, nme.GE, nme.LSL, nme.LSR, nme.ASR, nme.ADD, nme.SUB, nme.MUL, nme.DIV, nme.MOD) - private val foldedUnops = Set[Name]( + val foldedUnops = Set[Name]( nme.UNARY_!, nme.UNARY_~, nme.UNARY_+, nme.UNARY_-) def Apply[T <: Apply](tree: T)(using Context): T =