Skip to content

Commit 1f68f97

Browse files
committed
Use special method for converting Select qualifiers
1 parent bf490eb commit 1f68f97

File tree

2 files changed

+78
-47
lines changed

2 files changed

+78
-47
lines changed

compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -133,12 +133,12 @@ trait TypeAssigner {
133133
qualType
134134

135135
/** The type of the selection `tree`, where `qual1` is the typed qualifier part. */
136-
def selectionType(tree: untpd.RefTree, qual1: Tree)(using Context): Type = {
136+
def selectionType(tree: untpd.RefTree, qual1: Tree)(using Context): Type =
137137
var qualType = qual1.tpe.widenIfUnstable
138-
if (!qualType.hasSimpleKind && tree.name != nme.CONSTRUCTOR)
138+
if !qualType.hasSimpleKind && tree.name != nme.CONSTRUCTOR then
139139
// constructors are selected on typeconstructor, type arguments are passed afterwards
140140
qualType = errorType(em"$qualType takes type parameters", qual1.srcPos)
141-
else if (!qualType.isInstanceOf[TermType])
141+
else if !qualType.isInstanceOf[TermType] then
142142
qualType = errorType(em"$qualType is illegal as a selection prefix", qual1.srcPos)
143143

144144
def arrayElemType = qual1.tpe.widen match
@@ -164,7 +164,7 @@ trait TypeAssigner {
164164
if reallyExists(mbr) then qualType.select(name, mbr)
165165
else if qualType.isErroneous || name.toTermName == nme.ERROR then UnspecifiedErrorType
166166
else NoType
167-
}
167+
end selectionType
168168

169169
def importSuggestionAddendum(pt: Type)(using Context): String = ""
170170

compiler/src/dotty/tools/dotc/typer/Typer.scala

Lines changed: 74 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -548,53 +548,32 @@ class Typer extends Namer
548548
then
549549
report.error(StableIdentPattern(tree, pt), tree.srcPos)
550550

551-
def typedSelect(tree: untpd.Select, pt: Type, qual: Tree)(using Context): Tree = qual match {
551+
def typedSelect(tree0: untpd.Select, pt: Type, qual: Tree)(using Context): Tree = qual match
552552
case qual: ExtMethodApply =>
553553
qual.app
554554
case qual =>
555-
val untpdSelect = cpy.Select(tree)(qual, tree.name)
556-
def finalize(tp: Type) = assignType(untpdSelect, tp)
557-
val ownType = accessibleSelectionType(untpdSelect, qual)
555+
val selName = tree0.name
556+
val tree = cpy.Select(tree0)(qual, selName)
557+
def finalize(tp: Type) = assignType(tree, tp)
558+
val ownType = accessibleSelectionType(tree, qual)
558559
if ownType.exists then
559-
val select = assignType(untpdSelect, ownType)
560+
val select = assignType(tree, ownType)
560561
val select1 = toNotNullTermRef(select, pt)
561562

562-
if (tree.name.isTypeName) checkStable(qual.tpe, qual.srcPos, "type prefix")
563+
if selName.isTypeName then checkStable(qual.tpe, qual.srcPos, "type prefix")
563564
checkStableIdentPattern(select1, pt)
564565
ConstFold(select1)
565566
else if couldInstantiateTypeVar(qual.tpe.widen) then
566567
// try again with more defined qualifier type
567-
typedSelect(untpdSelect, pt, qual)
568+
typedSelect(tree, pt, qual)
568569
else if qual.tpe.derivesFrom(defn.DynamicClass)
569-
&& tree.name.isTermName && !isDynamicExpansion(untpdSelect)
570+
&& selName.isTermName && !isDynamicExpansion(tree)
570571
then
571572
if pt.isInstanceOf[FunOrPolyProto] || pt == AssignProto then finalize(TryDynamicCallType)
572-
else typedDynamicSelect(tree, Nil, pt)
573+
else typedDynamicSelect(tree0, Nil, pt)
573574
else
574-
finalize(notAMember(untpdSelect, qual))
575-
/*
576-
// try an extension method in scope
577-
try
578-
val nestedCtx = ctx.fresh.setNewTyperState()
579-
findRef(selName, WildcardType, ExtensionMethod, EmptyFlags, tree.srcPos) match
580-
case ref: TermRef =>
581-
val app = extMethodApply(untpd.ref(ref).withSpan(tree.span), tree, pt)
582-
if !nestedCtx.reporter.hasErrors then
583-
nestedCtx.typerState.commit()
584-
return app
585-
else for err <- nestedCtx.reporter.allErrors.take(1) do
586-
rememberSearchFailure(tree,
587-
SearchFailure(app.withType(FailedExtension(app, pt, err.msg))))
588-
catch case ex: TypeError =>
589-
rememberSearchFailure(tree,
590-
SearchFailure(tree.withType(NestedFailure(ex.toMessage, pt))))
591-
592-
593-
val nestedCtx = ctx.fresh.setNewTyperState()
594-
case _ =>
595-
EmptyTree*/
596-
597-
}
575+
finalize(notAMember(tree, qual))
576+
end typedSelect
598577

599578
def typedSelect(tree: untpd.Select, pt: Type)(using Context): Tree = {
600579
record("typedSelect")
@@ -2911,23 +2890,75 @@ class Typer extends Namer
29112890
}
29122891
}
29132892

2914-
/** If this tree is a select node `qual.name`, try to insert an implicit conversion
2915-
* `c` around `qual` so that `c(qual).name` conforms to `pt`.
2893+
/** If this tree is a select node `qual.name` that does not conform to `pt`,
2894+
* try to insert an implicit conversion `c` around `qual` so that
2895+
* `c(qual).name` conforms to `pt`.
29162896
*/
29172897
def tryInsertImplicitOnQualifier(tree: Tree, pt: Type, locked: TypeVars)(using Context): Option[Tree] = trace(i"try insert impl on qualifier $tree $pt") {
29182898
tree match {
2919-
case Select(qual, name) if name != nme.CONSTRUCTOR =>
2920-
val qualProto = SelectionProto(name, pt, NoViewsAllowed, privateOK = false)
2921-
tryEither {
2922-
val qual1 = adapt(qual, qualProto, locked)
2923-
if ((qual eq qual1) || summon[Context].reporter.hasErrors) None
2924-
else Some(typed(cpy.Select(tree)(untpd.TypedSplice(qual1), name), pt, locked))
2925-
} { (_, _) => None
2926-
}
2899+
case tree @ Select(qual, name) if name != nme.CONSTRUCTOR =>
2900+
val selProto = SelectionProto(name, pt, NoViewsAllowed, privateOK = false)
2901+
if selProto.isMatchedBy(qual.tpe) then None
2902+
else
2903+
tryEither {
2904+
val tree1 = tryExtensionOrConversion(tree, pt, qual, locked, NoViewsAllowed, privateOK = false)
2905+
if tree1.isEmpty then None
2906+
else Some(adapt(tree1, pt, locked))
2907+
} { (_, _) => None
2908+
}
29272909
case _ => None
29282910
}
29292911
}
29302912

2913+
/** Given a selection `qual.name`, try to convert to an extension method
2914+
* application `name(qual)` or insert an implicit conversion `c(qual).name`.
2915+
*/
2916+
def tryExtensionOrConversion
2917+
(tree: untpd.Select, pt: Type, qual: Tree, locked: TypeVars, compat: Compatibility, privateOK: Boolean)
2918+
(using Context): Tree =
2919+
2920+
def selectionProto = SelectionProto(tree.name, pt, compat, privateOK)
2921+
// try an extension method in scope
2922+
try
2923+
val nestedCtx = ctx.fresh.setNewTyperState()
2924+
findRef(tree.name, WildcardType, ExtensionMethod, EmptyFlags, qual.srcPos) match
2925+
case ref: TermRef =>
2926+
val app = extMethodApply(untpd.ref(ref).withSpan(tree.span), qual, pt)
2927+
if !nestedCtx.reporter.hasErrors then
2928+
nestedCtx.typerState.commit()
2929+
return app
2930+
for err <- nestedCtx.reporter.allErrors.take(1) do
2931+
rememberSearchFailure(qual,
2932+
SearchFailure(app.withType(FailedExtension(app, selectionProto, err.msg))))
2933+
case _ =>
2934+
catch case ex: TypeError =>
2935+
rememberSearchFailure(qual,
2936+
SearchFailure(qual.withType(NestedFailure(ex.toMessage, selectionProto))))
2937+
2938+
// try an implicit conversion or given extension
2939+
if ctx.mode.is(Mode.ImplicitsEnabled) && qual.tpe.isValueType then
2940+
trace(i"try insert impl on qualifier $tree $pt") {
2941+
val selProto = selectionProto
2942+
inferView(qual, selProto) match
2943+
case SearchSuccess(found: ExtMethodApply, _, _) =>
2944+
return found.app // nothing to check or adapt for extension method applications
2945+
case SearchSuccess(found, _, _) =>
2946+
checkImplicitConversionUseOK(found)
2947+
val qual1 = withoutMode(Mode.ImplicitsEnabled)(adapt(found, selProto, locked))
2948+
return typedSelect(tree, pt, qual1)
2949+
case failure: SearchFailure =>
2950+
if failure.isAmbiguous then
2951+
return (
2952+
if canDefineFurther(qual.tpe.widen) then
2953+
tryExtensionOrConversion(tree, pt, qual, locked, compat, privateOK)
2954+
else
2955+
err.typeMismatch(qual, selProto, failure.reason) // TODO: report NotAMember instead, but need to be aware of failure
2956+
)
2957+
rememberSearchFailure(qual, failure)
2958+
}
2959+
EmptyTree
2960+
end tryExtensionOrConversion
2961+
29312962
/** Perform the following adaptations of expression, pattern or type `tree` wrt to
29322963
* given prototype `pt`:
29332964
* (1) Resolve overloading

0 commit comments

Comments
 (0)