@@ -828,48 +828,61 @@ trait Namers extends MethodSynthesis {
828
828
}
829
829
}
830
830
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.
832
853
* At this point many values have the most specific possible
833
854
* 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
835
856
* those singleton types.
836
857
*
837
858
* However, the compilation of pattern matches into switch
838
859
* 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"
840
861
* 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
842
863
* 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.)
843
870
*/
844
871
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
872
884
}
885
+
873
886
/** Computes the type of the body in a ValDef or DefDef, and
874
887
* assigns the type to the tpt's node. Returns the type.
875
888
*/
@@ -879,7 +892,7 @@ trait Namers extends MethodSynthesis {
879
892
case _ => defnTyper.computeType(tree.rhs, pt)
880
893
}
881
894
882
- val defnTpe = widenIfNecessary(tree.symbol, rhsTpe, pt)
895
+ val defnTpe = dropIllegalStarTypes( widenIfNecessary(tree.symbol, rhsTpe, pt) )
883
896
tree.tpt defineType defnTpe setPos tree.pos.focus
884
897
tree.tpt.tpe
885
898
}
0 commit comments