Skip to content

Commit f564a52

Browse files
committed
moved logic from application to typer
1 parent 7afe554 commit f564a52

File tree

4 files changed

+51
-25
lines changed

4 files changed

+51
-25
lines changed

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

Lines changed: 3 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -901,30 +901,10 @@ trait Applications extends Compatibility {
901901
case _ => IgnoredProto(pt)
902902
// Do ignore other expected result types, since there might be an implicit conversion
903903
// on the result. We could drop this if we disallow unrestricted implicit conversions.
904-
def protogen(argsPrecises: List[Boolean] = Nil) =
905-
new FunProto(tree.args, resultProto)(this, tree.applyKind, argsPrecises = argsPrecises)(using argCtx(tree))
906-
var originalProto = protogen()
907-
def getFunTyped = typedExpr(tree.fun, originalProto)
904+
val originalProto =
905+
new FunProto(tree.args, resultProto)(this, tree.applyKind)(using argCtx(tree))
908906
record("typedApply")
909-
extension (tpe: Type) def getArgsPrecises: List[Boolean] = tpe.widen match
910-
case mt: MethodType =>
911-
mt.paramInfos.map {
912-
case v: TypeVar => v.origin.isPrecise
913-
case _ => false
914-
}
915-
case _ => Nil
916-
val stateBkp = ctx.typerState.snapshot()
917-
val fun1MaybePrecise = getFunTyped
918-
val funTpe = fun1MaybePrecise.tpe
919-
val argsPrecises = funTpe.getArgsPrecises
920-
val fun1 =
921-
// `fun` may be precise and from overloaded function. If so, then we need another typer pass, with the
922-
// proper precise enforcements on the relevant arguments
923-
if (argsPrecises.exists(b => b))
924-
ctx.typerState.resetTo(stateBkp)
925-
originalProto = protogen(argsPrecises)
926-
getFunTyped
927-
else fun1MaybePrecise
907+
val fun1 = typedExpr(tree.fun, originalProto)
928908

929909
// If adaptation created a tupled dual of `originalProto`, pick the right version
930910
// (tupled or not) of originalProto to proceed.

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

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -328,7 +328,7 @@ object ProtoTypes {
328328
case class FunProto(args: List[untpd.Tree], resType: Type)(
329329
typer: Typer,
330330
override val applyKind: ApplyKind,
331-
state: FunProtoState = new FunProtoState,
331+
private var state: FunProtoState = new FunProtoState,
332332
val constrainResultDeep: Boolean = false,
333333
val argsPrecises: List[Boolean] = Nil
334334
)(using protoCtx: Context)
@@ -343,6 +343,9 @@ object ProtoTypes {
343343
typer.isApplicableType(tp, args, resultType, keepConstraint && !args.exists(isPoly))
344344
}
345345

346+
def snapshot: FunProtoState = state
347+
def resetTo(prevState: FunProtoState): Unit = state = prevState
348+
346349
def derivedFunProto(
347350
args: List[untpd.Tree] = this.args,
348351
resultType: Type = this.resultType,

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

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3028,7 +3028,49 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
30283028
typed(tree, pt, locked)(using ctx.withSource(tree.source))
30293029
else if ctx.run.nn.isCancelled then
30303030
tree.withType(WildcardType)
3031-
else adapt(typedUnadapted(tree, pt, locked), pt, locked)
3031+
else
3032+
val tu = typedUnadapted(tree, pt, locked)
3033+
pt match
3034+
case pt : FunProto =>
3035+
extension (tpe: Type) def getArgsPrecises: List[Boolean] = tpe.widen match
3036+
case mt: MethodType =>
3037+
mt.paramInfos.map {
3038+
case v: TypeVar => v.origin.isPrecise
3039+
case _ => false
3040+
}
3041+
case _ => Nil
3042+
val argsPrecises = tu.tpe.getArgsPrecises
3043+
// if the function arguments are known to be precise, then we update the
3044+
// proto with this information and later propagate its state back to the
3045+
// original proto.
3046+
if (argsPrecises.contains(true))
3047+
val ptPrecises = pt.derivedFunProto(argsPrecises = argsPrecises)
3048+
val adapted = adapt(tu, ptPrecises, locked)
3049+
pt.resetTo(ptPrecises.snapshot)
3050+
adapted
3051+
// otherwise, we need to check for overloaded function, because in that
3052+
// case we may not know if the final adapted function will be precise.
3053+
else tu.tpe match
3054+
// the function is overloaded, so we preserve the typer and proto state,
3055+
// adapt the tree, and then check if the arguments should be considered as
3056+
// precise. if so, then we need to recover the typer state and proto
3057+
// state, and re-adapt the tree with the precise enforcement.
3058+
case v: TermRef if v.isOverloaded =>
3059+
val savedTyperState = ctx.typerState.snapshot()
3060+
val savedProtoState = pt.snapshot
3061+
val adaptedMaybePrecise = adapt(tu, pt, locked)
3062+
val argsPrecises = adaptedMaybePrecise.tpe.getArgsPrecises
3063+
if (argsPrecises.contains(true))
3064+
val ptPrecises = pt.derivedFunProto(argsPrecises = argsPrecises)
3065+
ctx.typerState.resetTo(savedTyperState)
3066+
pt.resetTo(savedProtoState)
3067+
val adapted = adapt(tu, ptPrecises, locked)
3068+
pt.resetTo(ptPrecises.snapshot)
3069+
adapted
3070+
else adaptedMaybePrecise
3071+
// the function is not overloaded or has precise arguments
3072+
case _ => adapt(tu, pt, locked)
3073+
case _ => adapt(tu, pt, locked)
30323074
}
30333075

30343076
def typed(tree: untpd.Tree, pt: Type = WildcardType)(using Context): Tree =

tests/neg/precise-type-params.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -207,3 +207,4 @@ object preciseInTheWrongPlaceError:
207207
@precise def err2: Unit = {} // error
208208
@precise val err3: Int = 0 // error
209209
class err4[A <: Int @precise] // error
210+
@precise object err5 // error

0 commit comments

Comments
 (0)