Skip to content

Commit

Permalink
Split out pre-typing and typing versions of namedTupleElementTypes, p…
Browse files Browse the repository at this point in the history
…rinter using pre-typing version
  • Loading branch information
aherlihy committed Jan 9, 2025
1 parent 6c7cdea commit a7a7528
Show file tree
Hide file tree
Showing 5 changed files with 11 additions and 12 deletions.
2 changes: 1 addition & 1 deletion compiler/src/dotty/tools/dotc/ast/Desugar.scala
Original file line number Diff line number Diff line change
Expand Up @@ -1744,7 +1744,7 @@ object desugar {
def adaptPatternArgs(elems: List[Tree], pt: Type)(using Context): List[Tree] =

def reorderedNamedArgs(wildcardSpan: Span): List[untpd.Tree] =
var selNames = pt.namedTupleElementTypes.map(_(0))
var selNames = pt.namedTupleElementTypes(false).map(_(0))
if selNames.isEmpty && pt.classSymbol.is(CaseClass) then
selNames = pt.classSymbol.caseAccessors.map(_.name.asTermName)
val nameToIdx = selNames.zipWithIndex.toMap
Expand Down
13 changes: 6 additions & 7 deletions compiler/src/dotty/tools/dotc/core/TypeUtils.scala
Original file line number Diff line number Diff line change
Expand Up @@ -127,23 +127,22 @@ class TypeUtils:
case Some(types) => TypeOps.nestedPairs(types)
case None => throw new AssertionError("not a tuple")

def namedTupleElementTypesUpTo(bound: Int, normalize: Boolean = true)(using Context): List[(TermName, Type)] =
if bound < 0 then Nil else
def namedTupleElementTypesUpTo(bound: Int, derived: Boolean, normalize: Boolean = true)(using Context): List[(TermName, Type)] =
(if normalize then self.normalized else self).dealias match
case defn.NamedTuple(nmes, vals) =>
val names = nmes.tupleElementTypesUpTo(bound, normalize).getOrElse(Nil).map(_.dealias).map:
case ConstantType(Constant(str: String)) => str.toTermName
case t => throw TypeError(em"Malformed NamedTuple: names must be string types, but $t was found.")
val values = vals.tupleElementTypesUpTo(bound, normalize).getOrElse(Nil)
names.zip(values)
case tp: TypeProxy =>
case tp: TypeProxy if derived =>
tp.superType.namedTupleElementTypesUpTo(bound - 1, normalize)
case tp: OrType =>
case tp: OrType if derived =>
val lhs = tp.tp1.namedTupleElementTypesUpTo(bound - 1, normalize)
val rhs = tp.tp2.namedTupleElementTypesUpTo(bound - 1, normalize)
if (lhs.map(_._1) != rhs.map(_._1)) throw TypeError(em"Malformed Union Type: Named Tuple elements must be the same, but $lhs and $rhs were found.")
lhs.zip(rhs).map((lhs, rhs) => (lhs._1, lhs._2 | rhs._2))
case tp: AndType =>
case tp: AndType if derived =>
(tp.tp1.namedTupleElementTypesUpTo(bound - 1, normalize), tp.tp2.namedTupleElementTypesUpTo(bound - 1, normalize)) match
case (Nil, rhs) => rhs
case (lhs, Nil) => lhs
Expand All @@ -153,8 +152,8 @@ class TypeUtils:
case t =>
Nil

def namedTupleElementTypes(using Context): List[(TermName, Type)] =
namedTupleElementTypesUpTo(Int.MaxValue)
def namedTupleElementTypes(derived: Boolean)(using Context): List[(TermName, Type)] =
namedTupleElementTypesUpTo(Int.MaxValue, derived)

def isNamedTupleType(using Context): Boolean = self match
case defn.NamedTuple(_, _) => true
Expand Down
2 changes: 1 addition & 1 deletion compiler/src/dotty/tools/dotc/interactive/Completion.scala
Original file line number Diff line number Diff line change
Expand Up @@ -532,7 +532,7 @@ object Completion:
def namedTupleCompletionsFromType(tpe: Type): CompletionMap =
val freshCtx = ctx.fresh.setExploreTyperState()
inContext(freshCtx):
tpe.namedTupleElementTypes
tpe.namedTupleElementTypes(true)
.map { (name, tpe) =>
val symbol = newSymbol(owner = NoSymbol, name, EmptyFlags, tpe)
val denot = SymDenotation(symbol, NoSymbol, name, EmptyFlags, tpe)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -248,7 +248,7 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) {
def appliedText(tp: Type): Text = tp match
case tp @ AppliedType(tycon, args) =>
val namedElems =
try tp.namedTupleElementTypesUpTo(200, normalize = false)
try tp.namedTupleElementTypesUpTo(200, false, normalize = false) // TODO: should the printer use derived or not?
catch case ex: TypeError => Nil
if namedElems.nonEmpty then
toTextNamedTuple(namedElems)
Expand Down
4 changes: 2 additions & 2 deletions compiler/src/dotty/tools/dotc/typer/Typer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -799,7 +799,7 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer

// Otherwise, try to expand a named tuple selection
def tryNamedTupleSelection() =
val namedTupleElems = qual.tpe.widenDealias.namedTupleElementTypes
val namedTupleElems = qual.tpe.widenDealias.namedTupleElementTypes(true)
val nameIdx = namedTupleElems.indexWhere(_._1 == selName)
if nameIdx >= 0 && Feature.enabled(Feature.namedTuples) then
typed(
Expand Down Expand Up @@ -875,7 +875,7 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
then
val pre = if !TypeOps.isLegalPrefix(qual.tpe) then SkolemType(qual.tpe) else qual.tpe
val fieldsType = pre.select(tpnme.Fields).widenDealias.simplified
val fields = fieldsType.namedTupleElementTypes
val fields = fieldsType.namedTupleElementTypes(true)
typr.println(i"try dyn select $qual, $selName, $fields")
fields.find(_._1 == selName) match
case Some((_, fieldType)) =>
Expand Down

0 comments on commit a7a7528

Please sign in to comment.