@@ -828,7 +828,28 @@ 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
855
* most need to be widened to avoid undesirable propagation of
@@ -841,35 +862,39 @@ trait Namers extends MethodSynthesis {
841
862
* value should not be widened, so it has a use even in situations
842
863
* whether it is otherwise redundant (such as in a singleton.)
843
864
*/
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
+ )
868
893
if (shouldWiden) tpe.widen
869
894
else if (sym.isFinal) tpe // "final val" allowed to retain constant type
870
895
else tpe.deconst
871
- )
872
- }
896
+ }
897
+
873
898
/** Computes the type of the body in a ValDef or DefDef, and
874
899
* assigns the type to the tpt's node. Returns the type.
875
900
*/
@@ -879,7 +904,7 @@ trait Namers extends MethodSynthesis {
879
904
case _ => defnTyper.computeType(tree.rhs, pt)
880
905
}
881
906
882
- val defnTpe = widenIfNecessary(tree.symbol, rhsTpe, pt)
907
+ val defnTpe = dropIllegalStarTypes( widenIfNecessary(tree.symbol, rhsTpe, pt) )
883
908
tree.tpt defineType defnTpe setPos tree.pos.focus
884
909
tree.tpt.tpe
885
910
}
0 commit comments