Skip to content

Commit d143271

Browse files
committed
widenIfNecessary
1 parent 359b140 commit d143271

File tree

1 file changed

+53
-28
lines changed

1 file changed

+53
-28
lines changed

src/compiler/scala/tools/nsc/typechecker/Namers.scala

Lines changed: 53 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -828,7 +828,28 @@ trait Namers extends MethodSynthesis {
828828
}
829829
}
830830

831-
/** This method has a big impact on the eventual compiled code.
831+
private def refersToSymbolLessAccessibleThan(tp: Type, sym: Symbol): Boolean = {
832+
val accessibilityReference =
833+
if (sym.isValue && sym.owner.isClass && sym.isPrivate)
834+
sym.getterIn(sym.owner)
835+
else sym
836+
837+
@tailrec def loop(tp: Type): Boolean = tp match {
838+
case SingleType(pre, sym) =>
839+
(sym isLessAccessibleThan accessibilityReference) || loop(pre)
840+
case ThisType(sym) =>
841+
sym isLessAccessibleThan accessibilityReference
842+
case p: SimpleTypeProxy =>
843+
loop(p.underlying)
844+
case _ =>
845+
false
846+
}
847+
848+
loop(tp)
849+
}
850+
851+
/**
852+
* This method has a big impact on the eventual compiled code.
832853
* At this point many values have the most specific possible
833854
* type (e.g. in val x = 42, x's type is Int(42), not Int) but
834855
* most need to be widened to avoid undesirable propagation of
@@ -841,35 +862,39 @@ trait Namers extends MethodSynthesis {
841862
* value should not be widened, so it has a use even in situations
842863
* whether it is otherwise redundant (such as in a singleton.)
843864
*/
844-
private def widenIfNecessary(sym: Symbol, tpe: Type, pt: Type): Type = {
845-
val getter =
846-
if (sym.isValue && sym.owner.isClass && sym.isPrivate)
847-
sym.getter(sym.owner)
848-
else sym
849-
def isHidden(tp: Type): Boolean = tp match {
850-
case SingleType(pre, sym) =>
851-
(sym isLessAccessibleThan getter) || isHidden(pre)
852-
case ThisType(sym) =>
853-
sym isLessAccessibleThan getter
854-
case p: SimpleTypeProxy =>
855-
isHidden(p.underlying)
856-
case _ =>
857-
false
858-
}
859-
val shouldWiden = (
860-
!tpe.typeSymbolDirect.isModuleClass // Infer Foo.type instead of "object Foo"
861-
&& (tpe.widen <:< pt) // Don't widen our way out of conforming to pt
862-
&& ( sym.isVariable
863-
|| sym.isMethod && !sym.hasAccessorFlag
864-
|| isHidden(tpe)
865-
)
866-
)
867-
dropIllegalStarTypes(
865+
private def widenIfNecessary(sym: Symbol, tpe: Type, pt: Type): Type =
866+
if (sip23) { // SIP-23
867+
// TODO: spec -- this is a crucial part of type inference
868+
// NOTES:
869+
// - Can we widen less? (E.g., for local definitions.)
870+
// - Do we need to check tpe.deconst <:< pt?
871+
// - We don't need to call dropIllegalStarTypes on a ref to a module class, do we? Where would the stars be? In the prefix?
872+
873+
// We're inferring the result type of a stable symbol, and the type doesn't refer to a hidden symbol
874+
val mayKeepSingletonType = sym.isStable && !refersToSymbolLessAccessibleThan(tpe, sym)
875+
876+
// (OPT: 99.99% of the time, pt will be WildcardType)
877+
@inline def cannotWiden = (pt ne WildcardType) && !(tpe.widen <:< pt)
878+
879+
// If the definition can keep its inferred singleton type,
880+
// or widening would mean no longer conforming to the expected type,
881+
// we must still deconst unless it's a final val. Otherwise, widen.
882+
if (mayKeepSingletonType || cannotWiden) { if (sym.isFinal) tpe else tpe.deconst }
883+
else tpe.widen
884+
} else {
885+
val shouldWiden = (
886+
!tpe.typeSymbolDirect.isModuleClass // Infer Foo.type instead of "object Foo"
887+
&& (tpe.widen <:< pt) // Don't widen our way out of conforming to pt
888+
&& ( sym.isVariable
889+
|| sym.isMethod && !sym.hasAccessorFlag
890+
|| refersToSymbolLessAccessibleThan(tpe, sym)
891+
)
892+
)
868893
if (shouldWiden) tpe.widen
869894
else if (sym.isFinal) tpe // "final val" allowed to retain constant type
870895
else tpe.deconst
871-
)
872-
}
896+
}
897+
873898
/** Computes the type of the body in a ValDef or DefDef, and
874899
* assigns the type to the tpt's node. Returns the type.
875900
*/
@@ -879,7 +904,7 @@ trait Namers extends MethodSynthesis {
879904
case _ => defnTyper.computeType(tree.rhs, pt)
880905
}
881906

882-
val defnTpe = widenIfNecessary(tree.symbol, rhsTpe, pt)
907+
val defnTpe = dropIllegalStarTypes(widenIfNecessary(tree.symbol, rhsTpe, pt))
883908
tree.tpt defineType defnTpe setPos tree.pos.focus
884909
tree.tpt.tpe
885910
}

0 commit comments

Comments
 (0)