-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Applied types, unoptimized #3061
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 110 commits
8fa29ad
7be50a6
2ec644b
b219c74
6a63549
4b64c00
76d1194
cf491ff
08ff2b2
b17f5de
9b59150
c3daec5
4a6df0e
0228613
c65c10a
83fb812
6c5106e
965a8e4
d947614
abde37e
ef086ce
357e2ae
f9520cb
842ac4b
baf6bf5
90fd77f
0e4a3ea
d71dc4b
850e5d9
584eaef
dcec2da
588f1dc
596fa17
5bfa153
b9f3084
756238e
471e62b
2b10447
27dbeef
a3d96f1
0a27a7f
891022b
52dd131
51e67d1
9f3b5a5
536c597
c4def34
6a02717
2da0049
9063347
b0a2aa2
36b1550
dcd8fd3
59ce28f
60d7b85
bec92d1
f92b5fc
184ff81
5a2c35d
4b34d68
25b9bb0
1daca6c
26a327d
95720b0
3c4b6bd
41d6d9e
88953fa
77077a5
89d9ef9
6f49cfd
e631f38
c3d44d7
812373f
adde88e
0b4c35c
f65162b
99f6bf2
0db4ed4
0fd92da
871a178
cdb34e5
babc490
a78c26f
f4d0942
b665f13
e3c3dda
80ce8d2
7de2c12
9c28187
476e952
77a09c7
5dd8846
636e30e
0a5dfe9
975a29b
db28f49
7cf4637
eddc4a4
417ca7e
8456b37
826f14e
196b008
0de8041
ad04a98
a0b6910
acb6165
48a2ab3
fe470c4
22440f3
d2b7080
2e65bd5
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -33,6 +33,12 @@ object CheckRealizable { | |
class HasProblemBounds(typ: SingleDenotation)(implicit ctx: Context) | ||
extends Realizability(i" has a member $typ with possibly conflicting bounds ${typ.info.bounds.lo} <: ... <: ${typ.info.bounds.hi}") | ||
|
||
class HasProblemBaseArg(typ: Type, argBounds: TypeBounds)(implicit ctx: Context) | ||
extends Realizability(i" has a base type $typ with possibly conflicting parameter bounds ${argBounds.lo} <: ... <: ${argBounds.hi}") | ||
|
||
class HasProblemBase(base1: Type, base2: Type)(implicit ctx: Context) | ||
extends Realizability(i" has conflicting base types $base1 and $base2") | ||
|
||
class HasProblemField(fld: SingleDenotation, problem: Realizability)(implicit ctx: Context) | ||
extends Realizability(i" has a member $fld which is not a legal path\n since ${fld.symbol.name}: ${fld.info}${problem.msg}") | ||
|
||
|
@@ -89,18 +95,39 @@ class CheckRealizable(implicit ctx: Context) { | |
else boundsRealizability(tp).andAlso(memberRealizability(tp)) | ||
} | ||
|
||
/** `Realizable` if `tp` has good bounds, a `HasProblemBounds` instance | ||
* pointing to a bad bounds member otherwise. | ||
/** `Realizable` if `tp` has good bounds, a `HasProblem...` instance | ||
* pointing to a bad bounds member otherwise. "Has good bounds" means: | ||
* | ||
* - all type members have good bounds | ||
* - all base types are class types, and if their arguments are wildcards | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Wait, why would we allow base type arguments to be wildcards? This does not compile with scalac: scala> class A[T]
defined class A
scala> class B extends A[_ <: String]
<console>:12: error: class type required but A[_ <: String] found
class B extends A[_ <: String]
^ There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why not? Also, conflicting bounds might arise by siplification of AndTypes. I expanded the explanation. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I guess for the same reason we don't want |
||
* they have good bounds. | ||
* - base types do not appear in multiple instances with different arguments. | ||
* (depending on the simplification scheme for AndTypes employed, this could | ||
* also lead to base types with bad bounds). | ||
*/ | ||
private def boundsRealizability(tp: Type) = { | ||
def hasBadBounds(mbr: SingleDenotation) = { | ||
val bounds = mbr.info.bounds | ||
!(bounds.lo <:< bounds.hi) | ||
} | ||
tp.nonClassTypeMembers.find(hasBadBounds) match { | ||
case Some(mbr) => new HasProblemBounds(mbr) | ||
case _ => Realizable | ||
val mbrProblems = | ||
for { | ||
mbr <- tp.nonClassTypeMembers | ||
if !(mbr.info.loBound <:< mbr.info.hiBound) | ||
} | ||
yield new HasProblemBounds(mbr) | ||
|
||
def baseTypeProblems(base: Type) = base match { | ||
case AndType(base1, base2) => | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Complication: Realizablility used to just check that all type members have good bounds. Now it has to look at basetypes as well. |
||
new HasProblemBase(base1, base2) :: Nil | ||
case base => | ||
base.argInfos.collect { | ||
case bounds @ TypeBounds(lo, hi) if !(lo <:< hi) => | ||
new HasProblemBaseArg(base, bounds) | ||
} | ||
} | ||
val baseProblems = | ||
tp.baseClasses.map(_.baseTypeOf(tp)).flatMap(baseTypeProblems) | ||
|
||
(((Realizable: Realizability) | ||
/: mbrProblems)(_ andAlso _) | ||
/: baseProblems)(_ andAlso _) | ||
} | ||
|
||
/** `Realizable` if all of `tp`'s non-struct fields have realizable types, | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -6,7 +6,7 @@ import Types._, Contexts._, Symbols._ | |
import Decorators._ | ||
import config.Config | ||
import config.Printers.{constr, typr} | ||
import TypeApplications.EtaExpansion | ||
import TypeApplications.{EtaExpansion, TypeParamInfo} | ||
import collection.mutable | ||
|
||
/** Methods for adding constraints and solving them. | ||
|
@@ -194,9 +194,14 @@ trait ConstraintHandling { | |
final def approximation(param: TypeParamRef, fromBelow: Boolean): Type = { | ||
val avoidParam = new TypeMap { | ||
override def stopAtStatic = true | ||
def avoidInArg(arg: Type): Type = | ||
if (param.occursIn(arg)) TypeBounds.empty else arg | ||
def apply(tp: Type) = mapOver { | ||
tp match { | ||
case tp: RefinedType if param occursIn tp.refinedInfo => tp.parent | ||
case tp @ AppliedType(tycon, args) => | ||
tp.derivedAppliedType(tycon, args.mapConserve(avoidInArg)) | ||
case tp: RefinedType if param occursIn tp.refinedInfo => | ||
tp.parent | ||
case tp: WildcardType => | ||
val bounds = tp.optBounds.orElse(TypeBounds.empty).bounds | ||
// Try to instantiate the wildcard to a type that is known to conform to it. | ||
|
@@ -306,7 +311,12 @@ trait ConstraintHandling { | |
/** The current bounds of type parameter `param` */ | ||
final def bounds(param: TypeParamRef): TypeBounds = { | ||
val e = constraint.entry(param) | ||
if (e.exists) e.bounds else param.binder.paramInfos(param.paramNum) | ||
if (e.exists) e.bounds | ||
else { | ||
val pinfos = param.binder.paramInfos | ||
if (pinfos != null) pinfos(param.paramNum) // pinfos == null happens in pos/i536.scala | ||
else TypeBounds.empty | ||
} | ||
} | ||
|
||
/** Add type lambda `tl`, possibly with type variables `tvars`, to current constraint | ||
|
@@ -318,7 +328,7 @@ trait ConstraintHandling { | |
checkPropagated(i"initialized $tl") { | ||
constraint = constraint.add(tl, tvars) | ||
tl.paramNames.indices.forall { i => | ||
val param = TypeParamRef(tl, i) | ||
val param = tl.paramRefs(i) | ||
val bounds = constraint.nonParamBounds(param) | ||
val lower = constraint.lower(param) | ||
val upper = constraint.upper(param) | ||
|
@@ -376,7 +386,12 @@ trait ConstraintHandling { | |
else tp | ||
|
||
def addParamBound(bound: TypeParamRef) = | ||
if (fromBelow) addLess(bound, param) else addLess(param, bound) | ||
constraint.entry(param) match { | ||
case _: TypeBounds => | ||
if (fromBelow) addLess(bound, param) else addLess(param, bound) | ||
case tp => | ||
if (fromBelow) isSubType(bound, tp) else isSubType(tp, bound) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Added case prompted by a failure. But it looks like we'd need it anyway, and we just failed to have a test that exercises this pass before. |
||
} | ||
|
||
/** Drop all constrained parameters that occur at the toplevel in `bound` and | ||
* handle them by `addLess` calls. | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -14,7 +14,6 @@ import NameOps._ | |
import Uniques._ | ||
import SymDenotations._ | ||
import Comments._ | ||
import Flags.ParamAccessor | ||
import util.Positions._ | ||
import ast.Trees._ | ||
import ast.untpd | ||
|
@@ -339,7 +338,7 @@ object Contexts { | |
* from constructor parameters to class parameter accessors. | ||
*/ | ||
def superCallContext: Context = { | ||
val locals = newScopeWith(owner.asClass.paramAccessors: _*) | ||
val locals = newScopeWith(owner.typeParams ++ owner.asClass.paramAccessors: _*) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Type parameters are no longer accessors, need to be mentioned explicitly. |
||
superOrThisCallContext(owner.primaryConstructor, locals) | ||
} | ||
|
||
|
@@ -609,20 +608,20 @@ object Contexts { | |
override def hash(x: Type): Int = x.hash | ||
} | ||
|
||
/** A table for hash consing unique refined types */ | ||
private[dotc] val uniqueRefinedTypes = new RefinedUniques | ||
/** A table for hash consing unique applied types */ | ||
private[dotc] val uniqueAppliedTypes = new AppliedUniques | ||
|
||
/** A table for hash consing unique named types */ | ||
private[core] val uniqueNamedTypes = new NamedTypeUniques | ||
|
||
/** A table for hash consing unique type bounds */ | ||
private[core] val uniqueTypeAliases = new TypeAliasUniques | ||
/** A table for hash consing unique symbolic named types */ | ||
private[core] val uniqueWithFixedSyms = new WithFixedSymUniques | ||
|
||
private def uniqueSets = Map( | ||
"uniques" -> uniques, | ||
"uniqueRefinedTypes" -> uniqueRefinedTypes, | ||
"uniqueNamedTypes" -> uniqueNamedTypes, | ||
"uniqueTypeAliases" -> uniqueTypeAliases) | ||
"uniqueAppliedTypes" -> uniqueAppliedTypes, | ||
"uniqueWithFixedSyms" -> uniqueWithFixedSyms, | ||
"uniqueNamedTypes" -> uniqueNamedTypes) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Optimize for different set of common types |
||
|
||
/** A map that associates label and size of all uniques sets */ | ||
def uniquesSizes: Map[String, Int] = uniqueSets.mapValues(_.size) | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Simplification: No paramForwarding or suspensions needed