Skip to content

Commit 9236c6c

Browse files
committed
precise given inferencing
1 parent 22fdca7 commit 9236c6c

15 files changed

+169
-71
lines changed

compiler/src/dotty/tools/dotc/core/ConstraintHandling.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -643,7 +643,7 @@ trait ConstraintHandling {
643643
if (tpw ne tp) && (tpw <:< bound) then tpw else tp
644644

645645
def isSingleton(tp: Type): Boolean = tp match
646-
case WildcardType(optBounds) => optBounds.exists && isSingleton(optBounds.bounds.hi)
646+
case WildcardType(optBounds, _) => optBounds.exists && isSingleton(optBounds.bounds.hi)
647647
case _ => isSubTypeWhenFrozen(tp, defn.SingletonType)
648648

649649
val wideInst =

compiler/src/dotty/tools/dotc/core/TypeApplications.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -383,7 +383,7 @@ class TypeApplications(val self: Type) extends AnyVal {
383383
case dealiased: LazyRef =>
384384
LazyRef.of(dealiased.ref.appliedTo(args))
385385
case dealiased: WildcardType =>
386-
WildcardType(dealiased.optBounds.orElse(TypeBounds.empty).appliedTo(args).bounds)
386+
WildcardType(dealiased.optBounds.orElse(TypeBounds.empty).appliedTo(args).bounds, dealiased.precise)
387387
case dealiased: TypeRef if dealiased.symbol == defn.NothingClass =>
388388
dealiased
389389
case dealiased =>

compiler/src/dotty/tools/dotc/core/Types.scala

Lines changed: 24 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -365,7 +365,7 @@ object Types {
365365
case TypeBounds(lo, hi) => lo.unusableForInference || hi.unusableForInference
366366
case tp: AndOrType => tp.tp1.unusableForInference || tp.tp2.unusableForInference
367367
case tp: LambdaType => tp.resultType.unusableForInference || tp.paramInfos.exists(_.unusableForInference)
368-
case WildcardType(optBounds) => optBounds.unusableForInference
368+
case WildcardType(optBounds, _) => optBounds.unusableForInference
369369
case CapturingType(parent, refs) => parent.unusableForInference || refs.elems.exists(_.unusableForInference)
370370
case _: ErrorType => true
371371
case _ => false
@@ -4533,7 +4533,7 @@ object Types {
45334533
def copyBoundType(bt: BT): Type = bt.paramRefs(paramNum)
45344534
private var preciseSubstitute: Boolean = false
45354535
private var cachedPrecise: Option[Boolean] = None
4536-
protected[Types] def setPreciseSubstitute(p: Boolean): Unit = preciseSubstitute = p
4536+
final protected[Types] def setPreciseSubstitute(p: Boolean): Unit = preciseSubstitute = p
45374537
private def isPreciseRecur(tp: Type, boringPrecise: Boolean)(using Context): Option[Boolean] = tp match
45384538
case p: TypeParamRef if p == this => Some(boringPrecise)
45394539
case at@AppliedType(_, args) =>
@@ -4551,12 +4551,17 @@ object Types {
45514551
// the param itself is annotated as precise or the param is first introduced
45524552
// in a precise position of an applied type argument
45534553
binder.paramPrecises(paramNum) ||
4554-
binder.resType.paramInfoss.view.flatten.flatMap(isPreciseRecur(_, false)).headOption.getOrElse(false)
4554+
(binder.resType match
4555+
//givens just return an applied type which we use
4556+
case at: AppliedType => isPreciseRecur(at, false)
4557+
//for method types we go over the arguments
4558+
case rt => rt.paramInfoss.view.flatten.flatMap(isPreciseRecur(_, false)).headOption
4559+
).getOrElse(false)
45554560
cachedPrecise = Some(precise)
45564561
precise
45574562
} ||
45584563
//the param upper-bounded by a precise type
4559-
ctx.typerState.constraint.upper(this).filter(_.paramName != this.paramName).exists(_.isPrecise)
4564+
ctx.typerState.constraint.minUpper(this).filter(_.paramName != this.paramName).exists(_.isPrecise)
45604565

45614566
/** Optimized version of occursIn, avoid quadratic blowup when solving
45624567
* constraints over large ground types.
@@ -5356,7 +5361,7 @@ object Types {
53565361
object TryDynamicCallType extends FlexType
53575362

53585363
/** Wildcard type, possibly with bounds */
5359-
abstract case class WildcardType(optBounds: Type) extends CachedGroundType with TermType {
5364+
abstract case class WildcardType(optBounds: Type, precise: Boolean) extends CachedGroundType with TermType {
53605365

53615366
def effectiveBounds(using Context): TypeBounds = optBounds match
53625367
case bounds: TypeBounds => bounds
@@ -5365,11 +5370,11 @@ object Types {
53655370
def derivedWildcardType(optBounds: Type)(using Context): WildcardType =
53665371
if (optBounds eq this.optBounds) this
53675372
else if (!optBounds.exists) WildcardType
5368-
else WildcardType(optBounds.asInstanceOf[TypeBounds])
5373+
else WildcardType(optBounds.asInstanceOf[TypeBounds], precise)
53695374

5370-
override def computeHash(bs: Binders): Int = doHash(bs, optBounds)
5375+
override def computeHash(bs: Binders): Int = doHash(bs, precise, optBounds)
53715376
override def hashIsStable: Boolean = optBounds.hashIsStable
5372-
5377+
override def isPrecise(using Context): Boolean = precise
53735378
override def eql(that: Type): Boolean = that match {
53745379
case that: WildcardType => optBounds.eq(that.optBounds)
53755380
case _ => false
@@ -5383,18 +5388,18 @@ object Types {
53835388
}
53845389
}
53855390

5386-
final class CachedWildcardType(optBounds: Type) extends WildcardType(optBounds)
5391+
final class CachedWildcardType(optBounds: Type, precise: Boolean) extends WildcardType(optBounds, precise)
53875392

5388-
@sharable object WildcardType extends WildcardType(NoType) {
5389-
def apply(bounds: TypeBounds)(using Context): WildcardType =
5393+
@sharable object WildcardType extends WildcardType(NoType, false) {
5394+
def apply(bounds: TypeBounds, precise: Boolean)(using Context): WildcardType =
53905395
if bounds eq TypeBounds.empty then
53915396
val result = ctx.base.emptyWildcardBounds
53925397
if result == null then
5393-
ctx.base.emptyWildcardBounds = unique(CachedWildcardType(bounds))
5394-
apply(bounds)
5398+
ctx.base.emptyWildcardBounds = unique(CachedWildcardType(bounds, precise))
5399+
apply(bounds, precise)
53955400
else
53965401
result
5397-
else unique(CachedWildcardType(bounds))
5402+
else unique(CachedWildcardType(bounds, precise))
53985403
}
53995404

54005405
/** An extractor for single abstract method types.
@@ -6090,7 +6095,11 @@ object Types {
60906095
val bounds = t.effectiveBounds
60916096
range(atVariance(-variance)(apply(bounds.lo)), apply(bounds.hi))
60926097
def apply(t: Type): Type = t match
6093-
case t: WildcardType => mapWild(t)
6098+
case t: WildcardType => mapWild(t) match
6099+
case tv: TypeVar =>
6100+
tv.origin.setPreciseSubstitute(t.isPrecise)
6101+
tv
6102+
case t => t
60946103
case _ => mapOver(t)
60956104

60966105
// ----- TypeAccumulators ----------------------------------------------------

compiler/src/dotty/tools/dotc/transform/Erasure.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1061,7 +1061,7 @@ object Erasure {
10611061
else adaptToType(tree, pt)
10621062
}
10631063

1064-
override def simplify(tree: Tree, pt: Type, locked: TypeVars)(using Context): tree.type = tree
1064+
override def simplify(tree: Tree, pt: Type, locked: TypeVars, skipPrecise: Boolean)(using Context): tree.type = tree
10651065
}
10661066

10671067
private def takesBridges(sym: Symbol)(using Context): Boolean =

compiler/src/dotty/tools/dotc/transform/PostTyper.scala

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -388,7 +388,8 @@ class PostTyper extends MacroTransform with IdentityDenotTransformer { thisPhase
388388
annotateExperimental(sym)
389389
tree.rhs match
390390
case impl: Template =>
391-
PreciseChecker.checkClass(impl)
391+
if (!sym.is(Flags.Given)) // skipping over given classes that are generated from `given ... with {}`
392+
PreciseChecker.checkClass(impl)
392393
for parent <- impl.parents do
393394
Checking.checkTraitInheritance(parent.tpe.classSymbol, sym.asClass, parent.srcPos)
394395
// Add SourceFile annotation to top-level classes

compiler/src/dotty/tools/dotc/transform/Recheck.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -301,7 +301,7 @@ abstract class Recheck extends Phase, SymTransformer:
301301
def recheckSeqLiteral(tree: SeqLiteral, pt: Type)(using Context): Type =
302302
val elemProto = pt.stripNull.elemType match
303303
case NoType => WildcardType
304-
case bounds: TypeBounds => WildcardType(bounds)
304+
case bounds: TypeBounds => WildcardType(bounds, pt.isPrecise)
305305
case elemtp => elemtp
306306
val declaredElemType = recheck(tree.elemtpt)
307307
val elemTypes = tree.elems.map(recheck(_, elemProto))

compiler/src/dotty/tools/dotc/transform/TreeChecker.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -638,7 +638,7 @@ class TreeChecker extends Phase with SymTransformer {
638638
tree
639639
}
640640

641-
override def simplify(tree: Tree, pt: Type, locked: TypeVars)(using Context): tree.type = tree
641+
override def simplify(tree: Tree, pt: Type, locked: TypeVars, skipPrecise: Boolean)(using Context): tree.type = tree
642642
}
643643

644644
/**

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

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import Contexts._, Types._, Flags._, Symbols._
88
import ProtoTypes._
99
import NameKinds.{AvoidNameKind, UniqueName}
1010
import util.Spans._
11-
import util.{Stats, SimpleIdentityMap, SrcPos}
11+
import util.{Stats, SimpleIdentityMap, SimpleIdentitySet, SrcPos}
1212
import Decorators._
1313
import config.Printers.{gadts, typr}
1414
import annotation.tailrec
@@ -574,17 +574,22 @@ trait Inferencing { this: Typer =>
574574
* Then `Y` also occurs co-variantly in `T` because it needs to be minimized in order to constrain
575575
* `T` the least. See `variances` for more detail.
576576
*/
577-
def interpolateTypeVars(tree: Tree, pt: Type, locked: TypeVars)(using Context): tree.type = {
577+
def interpolateTypeVars(tree: Tree, pt: Type, locked: TypeVars, skipPrecise: Boolean)(using Context): tree.type = {
578578
val state = ctx.typerState
579-
580579
// Note that some variables in `locked` might not be in `state.ownedVars`
581580
// anymore if they've been garbage-collected, so we can't use
582581
// `state.ownedVars.size > locked.size` as an early check to avoid computing
583582
// `qualifying`.
584583

585584
val ownedVars = state.ownedVars
586585
if ((ownedVars ne locked) && !ownedVars.isEmpty) {
587-
val qualifying = ownedVars -- locked
586+
val qualifying =
587+
@tailrec def stripInline(tree: Tree): Tree =
588+
tree match
589+
case Inlined(_,_,tree) => stripInline(tree)
590+
case _ => tree
591+
if (skipPrecise || stripInline(tree).symbol.is(Given)) (ownedVars -- locked).filter(!_.isPrecise)
592+
else ownedVars -- locked
588593
if (!qualifying.isEmpty) {
589594
typr.println(i"interpolate $tree: ${tree.tpe.widen} in $state, pt = $pt, owned vars = ${state.ownedVars.toList}%, %, qualifying = ${qualifying.toList}%, %, previous = ${locked.toList}%, % / ${state.constraint}")
590595
val resultAlreadyConstrained =

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

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -783,7 +783,7 @@ object ProtoTypes {
783783
|| ctx.mode.is(Mode.TypevarsMissContext)
784784
|| !ref.underlying.widenExpr.isValueTypeOrWildcard
785785
then
786-
WildcardType(ref.underlying.substParams(mt, mt.paramRefs.map(_ => WildcardType)).toBounds)
786+
WildcardType(ref.underlying.substParams(mt, mt.paramRefs.map(_ => WildcardType)).toBounds, ref.isPrecise)
787787
else
788788
newDepTypeVar(ref)
789789
mt.resultType.substParams(mt, mt.paramRefs.map(replacement))
@@ -841,7 +841,7 @@ object ProtoTypes {
841841
private def wildApprox(tp: Type, theMap: WildApproxMap | Null, seen: Set[TypeParamRef], internal: Set[TypeLambda])(using Context): Type = tp match {
842842
case tp: NamedType => // default case, inlined for speed
843843
val isPatternBoundTypeRef = tp.isInstanceOf[TypeRef] && tp.symbol.isPatternBound
844-
if (isPatternBoundTypeRef) WildcardType(tp.underlying.bounds)
844+
if (isPatternBoundTypeRef) WildcardType(tp.underlying.bounds, tp.isPrecise)
845845
else if (tp.symbol.isStatic || (tp.prefix `eq` NoPrefix)) tp
846846
else tp.derivedSelect(wildApprox(tp.prefix, theMap, seen, internal))
847847
case tp @ AppliedType(tycon, args) =>
@@ -865,7 +865,7 @@ object ProtoTypes {
865865
case tp @ TypeParamRef(poly, pnum) =>
866866
def wildApproxBounds(bounds: TypeBounds) =
867867
if (seen.contains(tp)) WildcardType
868-
else WildcardType(wildApprox(bounds, theMap, seen + tp, internal).bounds)
868+
else WildcardType(wildApprox(bounds, theMap, seen + tp, internal).bounds, tp.isPrecise)
869869
def unconstrainedApprox = wildApproxBounds(poly.paramInfos(pnum))
870870
def approxPoly =
871871
if (ctx.mode.is(Mode.TypevarsMissContext)) unconstrainedApprox
@@ -876,8 +876,8 @@ object ProtoTypes {
876876
case inst => wildApprox(inst, theMap, seen, internal)
877877
}
878878
approxPoly
879-
case TermParamRef(mt, pnum) =>
880-
WildcardType(TypeBounds.upper(wildApprox(mt.paramInfos(pnum), theMap, seen, internal)))
879+
case tp@TermParamRef(mt, pnum) =>
880+
WildcardType(TypeBounds.upper(wildApprox(mt.paramInfos(pnum), theMap, seen, internal)), tp.isPrecise)
881881
case tp: TypeVar =>
882882
wildApprox(tp.underlying, theMap, seen, internal)
883883
case tp: AndType =>
@@ -887,7 +887,7 @@ object ProtoTypes {
887887
def wildBounds(tp: Type) =
888888
if (tp.isInstanceOf[WildcardType]) tp.bounds else TypeBounds.upper(tp)
889889
if (tp1a.isInstanceOf[WildcardType] || tp2a.isInstanceOf[WildcardType])
890-
WildcardType(wildBounds(tp1a) & wildBounds(tp2a))
890+
WildcardType(wildBounds(tp1a) & wildBounds(tp2a), false)
891891
else
892892
tp.derivedAndType(tp1a, tp2a)
893893
}
@@ -897,7 +897,7 @@ object ProtoTypes {
897897
val tp1a = wildApprox(tp.tp1, theMap, seen, internal)
898898
val tp2a = wildApprox(tp.tp2, theMap, seen, internal)
899899
if (tp1a.isInstanceOf[WildcardType] || tp2a.isInstanceOf[WildcardType])
900-
WildcardType(tp1a.bounds | tp2a.bounds)
900+
WildcardType(tp1a.bounds | tp2a.bounds, false)
901901
else
902902
tp.derivedOrType(tp1a, tp2a)
903903
}

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

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1236,7 +1236,7 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
12361236
}
12371237
def interpolateWildcards = new TypeMap {
12381238
def apply(t: Type): Type = t match
1239-
case WildcardType(bounds: TypeBounds) =>
1239+
case WildcardType(bounds: TypeBounds, _) =>
12401240
newTypeVar(apply(bounds.orElse(TypeBounds.empty)).bounds)
12411241
case _ => mapOver(t)
12421242
}
@@ -1925,7 +1925,7 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
19251925
def typedSeqLiteral(tree: untpd.SeqLiteral, pt: Type)(using Context): SeqLiteral = {
19261926
val elemProto = pt.stripNull.elemType match {
19271927
case NoType => WildcardType
1928-
case bounds: TypeBounds => WildcardType(bounds)
1928+
case bounds: TypeBounds => WildcardType(bounds, pt.isPrecise)
19291929
case elemtp => elemtp
19301930
}
19311931

@@ -3030,12 +3030,12 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
30303030
}
30313031

30323032
/** Interpolate and simplify the type of the given tree. */
3033-
protected def simplify(tree: Tree, pt: Type, locked: TypeVars)(using Context): tree.type =
3033+
protected def simplify(tree: Tree, pt: Type, locked: TypeVars, skipPrecise: Boolean = false)(using Context): tree.type =
30343034
if !tree.denot.isOverloaded then // for overloaded trees: resolve overloading before simplifying
30353035
if !tree.tpe.widen.isInstanceOf[MethodOrPoly] // wait with simplifying until method is fully applied
30363036
|| tree.isDef // ... unless tree is a definition
30373037
then
3038-
interpolateTypeVars(tree, pt, locked)
3038+
interpolateTypeVars(tree, pt, locked, skipPrecise)
30393039
val simplified = tree.tpe.simplified
30403040
if !MatchType.thatReducesUsingGadt(tree.tpe) then // needs a GADT cast. i15743
30413041
tree.overwriteType(simplified)
@@ -3520,7 +3520,7 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
35203520
def methodStr = err.refStr(methPart(tree).tpe)
35213521

35223522
def readapt(tree: Tree)(using Context) = adapt(tree, pt, locked)
3523-
def readaptSimplified(tree: Tree)(using Context) = readapt(simplify(tree, pt, locked))
3523+
def readaptSimplified(tree: Tree, skipPrecise: Boolean = false)(using Context) = readapt(simplify(tree, pt, locked, skipPrecise))
35243524

35253525
def missingArgs(mt: MethodType) =
35263526
ErrorReporting.missingArgs(tree, mt)
@@ -3729,11 +3729,11 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
37293729
}
37303730
else tree match {
37313731
case tree: Block =>
3732-
readaptSimplified(tpd.Block(tree.stats, tpd.Apply(tree.expr, args)))
3732+
readaptSimplified(tpd.Block(tree.stats, tpd.Apply(tree.expr, args)), true)
37333733
case tree: NamedArg =>
3734-
readaptSimplified(tpd.NamedArg(tree.name, tpd.Apply(tree.arg, args)))
3734+
readaptSimplified(tpd.NamedArg(tree.name, tpd.Apply(tree.arg, args)), true)
37353735
case _ =>
3736-
readaptSimplified(tpd.Apply(tree, args))
3736+
readaptSimplified(tpd.Apply(tree, args), true)
37373737
}
37383738
}
37393739
pt.revealIgnored match {

0 commit comments

Comments
 (0)