Skip to content

Commit d71cd1c

Browse files
committed
Simplify widenIfNecessary (behavior should be same).
Rewrite `sym.isVariable || sym.isMethod && !sym.hasAccessorFlag` to `!sym.isStable`, and drop `!tpe.typeSymbolDirect.isModuleClass`, as we already infer Foo.type instead of "object Foo" upstream (there was no regression test for it, but verified this manually).
1 parent c33c967 commit d71cd1c

File tree

1 file changed

+45
-32
lines changed

1 file changed

+45
-32
lines changed

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

Lines changed: 45 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -828,48 +828,61 @@ 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
834-
* most need to be widened to avoid undesirable propagation of
855+
* most need to be widened (which deconsts) to avoid undesirable propagation of
835856
* those singleton types.
836857
*
837858
* However, the compilation of pattern matches into switch
838859
* statements depends on constant folding, which will only take
839-
* place for those values which aren't widened. The "final"
860+
* place for those values which aren't deconsted. The "final"
840861
* modifier is the present means of signaling that a constant
841-
* value should not be widened, so it has a use even in situations
862+
* value should not deconsted, so it has a use even in situations
842863
* whether it is otherwise redundant (such as in a singleton.)
864+
*
865+
* TODO: spec -- this is a crucial part of type inference
866+
*
867+
* NOTES:
868+
* - Can we keep more singleton types? (E.g., for local definitions.)
869+
* - Do we need to check tpe.deconst <:< pt? (Probably not, since ConstantTypes are not user-expressible.)
843870
*/
844871
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(
868-
if (shouldWiden) tpe.widen
869-
else if (sym.isFinal) tpe // "final val" allowed to retain constant type
870-
else tpe.deconst
871-
)
872+
// Are we inferring the result type of a stable symbol, whose type doesn't refer to a hidden symbol?
873+
// If we refer to an inaccessible symbol, let's hope widening will result in an expressible type.
874+
val mayKeepSingletonType = sym.isStable && !refersToSymbolLessAccessibleThan(tpe, sym)
875+
876+
// Only final vals may be constant folded, so deconst inferred type of other members.
877+
@inline def keepSingleton = if (sym.isFinal) tpe else tpe.deconst
878+
879+
// Only widen if the definition can't keep its inferred singleton type,
880+
// (Also keep singleton type if so indicated by the expected type `pt`
881+
// OPT: 99.99% of the time, `pt` will be `WildcardType`).
882+
if (mayKeepSingletonType || ((pt ne WildcardType) && !(tpe.widen <:< pt))) keepSingleton
883+
else tpe.widen
872884
}
885+
873886
/** Computes the type of the body in a ValDef or DefDef, and
874887
* assigns the type to the tpt's node. Returns the type.
875888
*/
@@ -879,7 +892,7 @@ trait Namers extends MethodSynthesis {
879892
case _ => defnTyper.computeType(tree.rhs, pt)
880893
}
881894

882-
val defnTpe = widenIfNecessary(tree.symbol, rhsTpe, pt)
895+
val defnTpe = dropIllegalStarTypes(widenIfNecessary(tree.symbol, rhsTpe, pt))
883896
tree.tpt defineType defnTpe setPos tree.pos.focus
884897
tree.tpt.tpe
885898
}

0 commit comments

Comments
 (0)