-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Refinements to skolemizaton #23513
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Refinements to skolemizaton #23513
Changes from 3 commits
7b9f0cb
0ee4c20
31cd178
bfa02e2
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -12,6 +12,7 @@ import collection.mutable | |
import reporting.* | ||
import Checking.{checkNoPrivateLeaks, checkNoWildcard} | ||
import cc.CaptureSet | ||
import util.Property | ||
import transform.Splicer | ||
|
||
trait TypeAssigner { | ||
|
@@ -273,33 +274,32 @@ trait TypeAssigner { | |
/** Substitute argument type `argType` for parameter `pref` in type `tp`, | ||
* skolemizing the argument type if it is not stable and `pref` occurs in `tp`. | ||
*/ | ||
odersky marked this conversation as resolved.
Show resolved
Hide resolved
|
||
def safeSubstParam(tp: Type, pref: ParamRef, argType: Type)(using Context): Type = { | ||
def safeSubstParam(tp: Type, pref: ParamRef, argType: Type, arg: Tree | Null = null)(using Context): Type = { | ||
val tp1 = tp.substParam(pref, argType) | ||
if ((tp1 eq tp) || argType.isStable) tp1 | ||
else tp.substParam(pref, SkolemType(argType.widen)) | ||
if (tp1 eq tp) || argType.isStable then tp1 | ||
else tp.substParam(pref, skolemizeArgType(argType.widen, arg)) | ||
} | ||
|
||
/** Substitute types of all arguments `args` for corresponding `params` in `tp`. | ||
* The number of parameters `params` may exceed the number of arguments. | ||
* In this case, only the common prefix is substituted. | ||
*/ | ||
def safeSubstParams(tp: Type, params: List[ParamRef], argTypes: List[Type])(using Context): Type = argTypes match { | ||
case argType :: argTypes1 => | ||
val tp1 = safeSubstParam(tp, params.head, argType) | ||
safeSubstParams(tp1, params.tail, argTypes1) | ||
def safeSubstParams(tp: Type, params: List[ParamRef], args: List[Tree])(using Context): Type = args match | ||
case arg :: args1 => | ||
val tp1 = safeSubstParam(tp, params.head, arg.tpe, arg) | ||
safeSubstParams(tp1, params.tail, args1) | ||
case Nil => | ||
tp | ||
} | ||
|
||
def safeSubstMethodParams(mt: MethodType, argTypes: List[Type])(using Context): Type = | ||
if mt.isResultDependent then safeSubstParams(mt.resultType, mt.paramRefs, argTypes) | ||
def safeSubstMethodParams(mt: MethodType, args: List[Tree])(using Context): Type = | ||
if mt.isResultDependent then safeSubstParams(mt.resultType, mt.paramRefs, args) | ||
else mt.resultType | ||
|
||
def assignType(tree: untpd.Apply, fn: Tree, args: List[Tree])(using Context): Apply = { | ||
val ownType = fn.tpe.widen match { | ||
case fntpe: MethodType => | ||
if fntpe.paramInfos.hasSameLengthAs(args) || ctx.phase.prev.relaxedTyping then | ||
if fntpe.isResultDependent then safeSubstMethodParams(fntpe, args.tpes) | ||
if fntpe.isResultDependent then safeSubstMethodParams(fntpe, args) | ||
else fntpe.resultType // fast path optimization | ||
else | ||
val erroringPhase = | ||
|
@@ -570,6 +570,27 @@ trait TypeAssigner { | |
} | ||
|
||
object TypeAssigner extends TypeAssigner: | ||
|
||
/** An attachment on an argument in an application indicating that the argument's | ||
* type was converted to the given skolem type. | ||
*/ | ||
private val Skolemized = new Property.StickyKey[SkolemType] | ||
|
||
/** A skolem type wrapping `argType`, associated with `arg` if it is non-null. | ||
* Skolem types for the same arguments with equal underlying `argType`s are re-used. | ||
*/ | ||
def skolemizeArgType(argType: Type, arg: tpd.Tree | Null)(using Context): Type = | ||
if arg == null then | ||
SkolemType(argType) | ||
else | ||
arg.getAttachment(Skolemized) match | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Couldn't it happen that the same argument tree is shared among different application trees? In that case, wouldn't that be wrong to give them the same skolem type? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, that's indeed a concern. We don't usually share trees but we don't have a guarantee here. |
||
case Some(sk @ SkolemType(tp)) if argType frozen_=:= tp => | ||
sk | ||
case _ => | ||
val sk = SkolemType(argType) | ||
arg.putAttachment(Skolemized, sk) | ||
sk | ||
|
||
def seqLitType(tree: untpd.SeqLiteral, elemType: Type)(using Context) = tree match | ||
case tree: untpd.JavaSeqLiteral => defn.ArrayOf(elemType) | ||
case _ => if ctx.erasedTypes then defn.SeqType else defn.SeqType.appliedTo(elemType) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
import scala.language.experimental.modularity | ||
|
||
class Box1[T <: Singleton](val x: T) | ||
class Box2[T : Singleton](x: => T) | ||
def id(x: Int): x.type = x | ||
def readInt(): Int = ??? | ||
|
||
def Test = () | ||
val x = Box1(id(readInt())) | ||
|
||
val _: Box1[? <: Int] = x | ||
|
||
val y = Box2(id(readInt())) |
Uh oh!
There was an error while loading. Please reload this page.