Skip to content

Native applied types #3033

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

Closed
wants to merge 105 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
105 commits
Select commit Hold shift + click to select a range
44aae03
Introduce AppliedType
odersky Jul 21, 2017
5a34071
Adapt operations in Types
odersky Jul 21, 2017
2eeef2e
Move givenSelfType to ClassSymbol
odersky Jul 22, 2017
ab87816
Handle AppliedTypes
odersky Jul 23, 2017
b779514
Introduce TypeArgRef
odersky Jul 26, 2017
87506ad
Various fixes
odersky Jul 28, 2017
102bfdc
More fixes
odersky Jul 28, 2017
c2c5bce
Fix stray brace
odersky Jul 29, 2017
bdd72bd
Fix typing of _* arguments
odersky Jul 30, 2017
7747ad1
Fix rebase breakage
odersky Aug 16, 2017
a273d37
Fix debug output to make it more stable
odersky Aug 16, 2017
1be4904
Fix Stackoverflow in asSeenFrom
odersky Aug 16, 2017
a8762ce
Make newScheme non-final
odersky Aug 16, 2017
4837f94
Partially revert change in TypeApplications#Reducer
odersky Aug 16, 2017
71f93a6
Use atVariance for new cases in TypeMaps and TypeAccumulators
odersky Aug 16, 2017
67724ba
Fix bounds propagation
odersky Aug 17, 2017
4857f1b
Fix variance in avoidParams
odersky Aug 17, 2017
5331b1c
Fix isSubArg
odersky Aug 17, 2017
946942b
Avoid infinite expansion in normaizeWildcardArgs
odersky Aug 17, 2017
81f28c6
Handle parameters from base classes of package objects
odersky Aug 17, 2017
25d0752
More fixes
odersky Aug 18, 2017
0edead7
Fix #536 again
odersky Aug 18, 2017
f034fbb
Adapt ClassTypeParamCreationFlags to new scheme
odersky Aug 18, 2017
a5512b4
Fix TypeArgRef and argForParam
odersky Aug 18, 2017
6fdbc03
Add capture conversion
odersky Aug 18, 2017
36c4d3c
Fix ExpandSAMs
odersky Aug 18, 2017
002eb53
Fix implicit scope computation
odersky Aug 18, 2017
ab93593
Refine typeMismatchMsg
odersky Aug 19, 2017
6a84827
Generalize argForParam
odersky Aug 19, 2017
1ffba89
Check that class type parameters are only referenced via their this-t…
odersky Aug 20, 2017
77bfc57
Check that class type parameters are only referenced via their this-t…
odersky Aug 20, 2017
987ea23
Fix illegal select in VCInlineMethods
odersky Aug 20, 2017
6691f5c
Fix classBound
odersky Aug 21, 2017
9331807
Fix t8280
odersky Aug 21, 2017
21886ed
Adapt flip in Applications to new scheme
odersky Aug 21, 2017
e3489a6
Fix type of outer accessor
odersky Aug 21, 2017
a362c9a
Fix computation of implicit scope
odersky Aug 22, 2017
03f1f3d
Fix problem in isSubArg
odersky Aug 22, 2017
159edb0
Fix instantiatability checking
odersky Aug 23, 2017
2388ac0
Adapt tpd.ClassDef and tpd.AnonClass to new scheme
odersky Aug 23, 2017
394159e
Change capture conversion
odersky Aug 23, 2017
4bfc1eb
Fix variances for wildcard arguments in TypeMaps and TypeAccumulators
odersky Aug 23, 2017
55c6784
Avoid cyclic reference in normalizeWildcardArgs
odersky Aug 23, 2017
24389ff
Fix SuperAccessors
odersky Aug 23, 2017
d7eb9bd
Fix possible hole in constraint handling
odersky Aug 24, 2017
280d400
Fix
odersky Aug 24, 2017
615b1a2
Fix printing of TypeBounds
odersky Aug 24, 2017
86f6784
Refine Space#refine to handle AppliedTypes
odersky Aug 24, 2017
074ad5a
Fix implicit selection for views
odersky Aug 25, 2017
7392bb1
Fix sigName for AppliedType
odersky Aug 26, 2017
da10965
Handle Java raw types in isSubType
odersky Aug 27, 2017
ad27c84
Don't check variances when comparing type lambdas in Scala2 mode
odersky Aug 27, 2017
a431472
Don't try to simplify & / | types written as types
odersky Aug 27, 2017
6e5454b
Hash-cons applied types in their own table
odersky Aug 27, 2017
45db4c4
Make ParamRefs unique types.
odersky Aug 27, 2017
ff882cc
Refine statistics
odersky Aug 27, 2017
f4456d8
Make ParamRefs unique types.
odersky Aug 28, 2017
60af052
Make bound types be uniquely created by their binders
odersky Aug 28, 2017
9abfb58
More detailed stats
odersky Aug 29, 2017
3ef0f7b
Fix base type computation
odersky Aug 29, 2017
ab99dd0
Fix tests
odersky Aug 29, 2017
c21c05e
Temporarily disable pattern-matching exhaustivity tests
odersky Aug 29, 2017
c4daf0a
Temporarily weaken double definition check
odersky Aug 29, 2017
c2066e3
Temporarily existentials test to pending
odersky Aug 29, 2017
c1edae6
Ensure type correctness of repeated arguments
odersky Aug 30, 2017
4fd1d44
Update "good bounds" checks
odersky Aug 30, 2017
193dc7a
Exclude mixin forwarders from double definition checks
odersky Aug 31, 2017
bfcd599
Adapt superclass inference to new scheme
odersky Aug 31, 2017
db6e631
Avoid inifinite loop when comparing & types with class types
odersky Aug 31, 2017
f53f2ff
Fix rebase breakage
odersky Aug 31, 2017
84de2ee
Handle TypeArgRefs in UserfacingPrinter
odersky Aug 31, 2017
a5eafdd
Fix imports and add explanations in Space
odersky Aug 31, 2017
35c7a0d
Eliminate Config switches
odersky Aug 31, 2017
20a4a78
Get rid of parentRefs and associated operations
odersky Aug 31, 2017
bb842ca
Re-normalize parents methods
odersky Aug 31, 2017
d984f0b
Fix rebase breakage, drop old UserfacingPrinter
odersky Aug 31, 2017
833d911
Use adaptHkVariances when comparing type arguments
odersky Aug 31, 2017
dce68e6
Re-apply change to printing TypeArgRefs in UserfacingPrinter
odersky Aug 31, 2017
a87d3db
Fix script check file
odersky Aug 31, 2017
356e8f6
Drop HKApply
odersky Aug 31, 2017
0a80a7a
Make baseTypeOf more robust
odersky Aug 31, 2017
a344cab
Drop uniqueRefinedType and uniqueTypeAlias
odersky Aug 31, 2017
5227478
Drop variance in TypeAlias
odersky Aug 31, 2017
2e6de77
Fix equals for TypeAlias
odersky Aug 31, 2017
9f41699
Adapt homogenizeArgs to new scheme
odersky Sep 1, 2017
fd1943d
Drop AnyAppliedType
odersky Sep 1, 2017
19e6fbb
Fix printing of infix types
odersky Sep 1, 2017
d259aa9
Drop TypeParamAccessor
odersky Sep 1, 2017
f3535b5
Drop BaseTypeArg flag
odersky Sep 1, 2017
e38885e
Drop withoutArgs
odersky Sep 1, 2017
f2f2571
Drop ClassDenotation.appliedRef and ClassInfo.typeRef
odersky Sep 1, 2017
695b56f
Reorder and clean up erasure and sigName
odersky Sep 1, 2017
eeb1e86
More cleanups and removals of now redundant code
odersky Sep 2, 2017
df1c3c2
Better implementation of mapArgs
odersky Sep 2, 2017
9dfdeec
Specialize hash-consing of WithFixedSym types
odersky Sep 3, 2017
d92e3e6
Avoid creating unnecessary new lists in mapArgs
odersky Sep 4, 2017
fb82b09
Rework substituters
odersky Sep 4, 2017
fc83c24
Some further optimizations on Substituters
odersky Sep 4, 2017
3034f59
Optimize asSeenFrom for applied types
odersky Sep 4, 2017
1e6572d
More detailed stats
odersky Sep 4, 2017
7204538
Optimize wildApprox for applied types
odersky Sep 4, 2017
393d91f
Optimize simplify for applied types
odersky Sep 4, 2017
9af7324
Reverted: Refine Space#refine to handle AppliedTypes
odersky Sep 4, 2017
922b379
Fix test
odersky Sep 4, 2017
a7ec349
Some polishings
odersky Sep 4, 2017
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 11 additions & 10 deletions compiler/src/dotty/tools/dotc/Run.scala
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ class Run(comp: Compiler, ictx: Context) {
compileUnits()(ctx)
}

protected def compileUnits()(implicit ctx: Context) = Stats.monitorHeartBeat {
protected def compileUnits()(implicit ctx: Context) = Stats.maybeMonitored {
ctx.checkSingleThreaded()

// If testing pickler, make sure to stop after pickling phase:
Expand All @@ -118,17 +118,18 @@ class Run(comp: Compiler, ictx: Context) {
ctx.usePhases(phases)
var lastPrintedTree: PrintedTree = NoPrintedTree
for (phase <- ctx.allPhases)
if (phase.isRunnable) {
val start = System.currentTimeMillis
units = phase.runOn(units)
if (ctx.settings.Xprint.value.containsPhase(phase)) {
for (unit <- units) {
lastPrintedTree =
printTree(lastPrintedTree)(ctx.fresh.setPhase(phase.next).setCompilationUnit(unit))
if (phase.isRunnable)
Stats.trackTime(s"$phase ms ") {
val start = System.currentTimeMillis
units = phase.runOn(units)
if (ctx.settings.Xprint.value.containsPhase(phase)) {
for (unit <- units) {
lastPrintedTree =
printTree(lastPrintedTree)(ctx.fresh.setPhase(phase.next).setCompilationUnit(unit))
}
}
ctx.informTime(s"$phase ", start)
}
ctx.informTime(s"$phase ", start)
}
if (!ctx.reporter.hasErrors) Rewrites.writeBack()
for (unit <- units)
Stats.record("retained typed trees at end", unit.tpdTree.treeSize)
Expand Down
25 changes: 4 additions & 21 deletions compiler/src/dotty/tools/dotc/ast/Desugar.scala
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ package ast
import core._
import util.Positions._, Types._, Contexts._, Constants._, Names._, NameOps._, Flags._
import SymDenotations._, Symbols._, StdNames._, Annotations._, Trees._
import Decorators._
import Decorators._, transform.SymUtils._
import NameKinds.{UniqueName, EvidenceParamName, DefaultGetterName}
import language.higherKinds
import typer.FrontEnd
Expand Down Expand Up @@ -70,7 +70,7 @@ object desugar {
def apply(tp: Type) = tp match {
case tp: NamedType if tp.symbol.exists && (tp.symbol.owner eq originalOwner) =>
val defctx = ctx.outersIterator.dropWhile(_.scope eq ctx.scope).next()
var local = defctx.denotNamed(tp.name).suchThat(_ is ParamOrAccessor).symbol
var local = defctx.denotNamed(tp.name).suchThat(_.isParamOrAccessor).symbol
if (local.exists) (defctx.owner.thisType select local).dealias
else {
def msg =
Expand Down Expand Up @@ -238,23 +238,6 @@ object desugar {
Nil
}

/** Fill in empty type bounds with Nothing/Any. Expand private local type parameters as follows:
*
* class C[v T]
* ==>
* class C { type v C$T; type v T = C$T }
*/
def typeDef(tdef: TypeDef)(implicit ctx: Context): Tree = {
if (tdef.mods is PrivateLocalParam) {
val tparam = cpy.TypeDef(tdef)(name = tdef.name.expandedName(ctx.owner))
.withMods(tdef.mods &~ PrivateLocal)
val alias = cpy.TypeDef(tdef)(rhs = refOfDef(tparam))
.withMods(tdef.mods & VarianceFlags | PrivateLocalParamAccessor | Synthetic)
Thicket(tparam, alias)
}
else tdef
}

@sharable private val synthetic = Modifiers(Synthetic)

private def toDefParam(tparam: TypeDef): TypeDef =
Expand Down Expand Up @@ -696,7 +679,7 @@ object desugar {

def defTree(tree: Tree)(implicit ctx: Context): Tree = tree match {
case tree: ValDef => valDef(tree)
case tree: TypeDef => if (tree.isClassDef) classDef(tree) else typeDef(tree)
case tree: TypeDef => if (tree.isClassDef) classDef(tree) else tree
case tree: DefDef => defDef(tree)
case tree: ModuleDef => moduleDef(tree)
case tree: PatDef => patDef(tree)
Expand Down Expand Up @@ -1132,7 +1115,7 @@ object desugar {
*/
def refinedTypeToClass(parent: tpd.Tree, refinements: List[Tree])(implicit ctx: Context): TypeDef = {
def stripToCore(tp: Type): List[Type] = tp match {
case tp: RefinedType if tp.argInfos.nonEmpty => tp :: Nil // parameterized class type
case tp: AppliedType => tp :: Nil
case tp: TypeRef if tp.symbol.isClass => tp :: Nil // monomorphic class type
case tp: TypeProxy => stripToCore(tp.underlying)
case AndType(tp1, tp2) => stripToCore(tp1) ::: stripToCore(tp2)
Expand Down
13 changes: 7 additions & 6 deletions compiler/src/dotty/tools/dotc/ast/tpd.scala
Original file line number Diff line number Diff line change
Expand Up @@ -213,8 +213,7 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
ta.assignType(untpd.TypeDef(sym.name, TypeTree(sym.info)), sym)

def ClassDef(cls: ClassSymbol, constr: DefDef, body: List[Tree], superArgs: List[Tree] = Nil)(implicit ctx: Context): TypeDef = {
val firstParentRef :: otherParentRefs = cls.info.parents
val firstParent = cls.typeRef.baseTypeWithArgs(firstParentRef.symbol)
val firstParent :: otherParents = cls.info.parents
val superRef =
if (cls is Trait) TypeTree(firstParent)
else {
Expand All @@ -229,7 +228,7 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
val constr = firstParent.decl(nme.CONSTRUCTOR).suchThat(constr => isApplicable(constr.info))
New(firstParent, constr.symbol.asTerm, superArgs)
}
val parents = superRef :: otherParentRefs.map(TypeTree(_))
val parents = superRef :: otherParents.map(TypeTree(_))

val selfType =
if (cls.classInfo.selfInfo ne NoType) ValDef(ctx.newSelfSym(cls))
Expand Down Expand Up @@ -305,7 +304,7 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
true
case pre: ThisType =>
pre.cls.isStaticOwner ||
tp.symbol.is(ParamOrAccessor) && !pre.cls.is(Trait) && ctx.owner.enclosingClass == pre.cls
tp.symbol.isParamOrAccessor && !pre.cls.is(Trait) && ctx.owner.enclosingClass == pre.cls
// was ctx.owner.enclosingClass.derivesFrom(pre.cls) which was not tight enough
// and was spuriously triggered in case inner class would inherit from outer one
// eg anonymous TypeMap inside TypeMap.andThen
Expand Down Expand Up @@ -381,7 +380,7 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
/** new C(args), calling given constructor `constr` of C */
def New(tp: Type, constr: TermSymbol, args: List[Tree])(implicit ctx: Context): Apply = {
val targs = tp.argTypes
val tycon = tp.withoutArgs(targs)
val tycon = tp.typeConstructor
New(tycon)
.select(TermRef.withSig(tycon, constr))
.appliedToTypes(targs)
Expand Down Expand Up @@ -698,8 +697,10 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
*/
def select(sym: Symbol)(implicit ctx: Context): Select = {
val tp =
if (sym.isType)
if (sym.isType) {
assert(!sym.is(TypeParam))
TypeRef(tree.tpe, sym.name.asTypeName)
}
else
TermRef.withSigAndDenot(tree.tpe, sym.name.asTermName,
sym.signature, sym.denot.asSeenFrom(tree.tpe))
Expand Down
4 changes: 2 additions & 2 deletions compiler/src/dotty/tools/dotc/ast/untpd.scala
Original file line number Diff line number Diff line change
Expand Up @@ -296,9 +296,9 @@ object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo {
(tycon, targs)
case TypedSplice(AppliedTypeTree(tycon, targs)) =>
(TypedSplice(tycon), targs map (TypedSplice(_)))
case TypedSplice(tpt1: Tree) =>
case TypedSplice(tpt1: tpd.Tree) =>
val tycon = tpt1.tpe.typeConstructor
val argTypes = tpt1.tpe.argTypesLo
val tycon = tpt1.tpe.withoutArgs(argTypes)
def wrap(tpe: Type) = TypeTree(tpe) withPos tpt.pos
(wrap(tycon), argTypes map wrap)
case _ =>
Expand Down
20 changes: 10 additions & 10 deletions compiler/src/dotty/tools/dotc/config/Config.scala
Original file line number Diff line number Diff line change
Expand Up @@ -84,19 +84,12 @@ object Config {
/** If this flag is set, take the fast path when comparing same-named type-aliases and types */
final val fastPathForRefinedSubtype = true

/** If this flag is set, `TypeOps.normalizeToClassRefs` will insert forwarders
* for type parameters of base classes. This is an optimization, which avoids
* long alias chains. We should not rely on the optimization, though. So changing
* the flag to false can be used for checking that everything works OK without it.
*/
final val forwardTypeParams = true

/** If this flag is set, and we compute `T1 { X = S1 }` & `T2 { X = S2 }` as a new
* upper bound of a constrained parameter, try to align the refinements by computing
/** If this flag is set, and we compute `T1[X1]` & `T2[X2]` as a new
* upper bound of a constrained parameter, try to align the arguments by computing
* `S1 =:= S2` (which might instantiate type parameters).
* This rule is contentious because it cuts the constraint set.
*
* For more info, see the comment in `TypeComparer#distributeAnd`.
* For more info, see the comment in `TypeComparer#glbArgs`.
*/
final val alignArgsInAnd = true

Expand All @@ -113,6 +106,13 @@ object Config {
*/
final val checkTypeRefCycles = false

/** If this flag is set, it is checked that class type parameters are
* only references with NoPrefix or ThisTypes as prefixes. This option
* is usally disabled, because there are still some legitimate cases where
* this can arise (e.g. for pos/Map.scala, in LambdaType.integrate).
*/
final val checkTypeParamRefs = false

/** The recursion depth for showing a summarized string */
final val summarizeDepth = 2

Expand Down
4 changes: 2 additions & 2 deletions compiler/src/dotty/tools/dotc/config/ScalaSettings.scala
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,6 @@ class ScalaSettings extends Settings.SettingGroup {
val Ycheck = PhasesSetting("-Ycheck", "Check the tree at the end of")
val YcheckMods = BooleanSetting("-Ycheck-mods", "Check that symbols and their defining trees have modifiers in sync")
val debug = BooleanSetting("-Ydebug", "Increase the quantity of debugging output.")
val debugAlias = BooleanSetting("-Ydebug-alias", "Never follow alias when printing types")
val debugTrace = BooleanSetting("-Ydebug-trace", "Trace core operations")
val debugFlags = BooleanSetting("-Ydebug-flags", "Print all flags of definitions")
val debugNames = BooleanSetting("-Ydebug-names", "Show internal representation of names")
Expand All @@ -87,7 +86,8 @@ class ScalaSettings extends Settings.SettingGroup {
val YmethodInfer = BooleanSetting("-Yinfer-argument-types", "Infer types for arguments of overriden methods.")
val YtraceContextCreation = BooleanSetting("-Ytrace-context-creation", "Store stack trace of context creations.")
val YshowSuppressedErrors = BooleanSetting("-Yshow-suppressed-errors", "Also show follow-on errors and warnings that are normally supressed.")
val Yheartbeat = BooleanSetting("-Yheartbeat", "show heartbeat stack trace of compiler operations.")
val YdetailedStats = BooleanSetting("-Ydetailed-stats", "show detailed internal compiler stats (needs Stats.enabled to be set to true).")
val Yheartbeat = BooleanSetting("-Ydetailed-stats", "show heartbeat stack trace of compiler operations (needs Stats.enabled to be set to true).")
val Yprintpos = BooleanSetting("-Yprintpos", "show tree positions.")
val YnoDeepSubtypes = BooleanSetting("-Yno-deep-subtypes", "throw an exception on deep subtyping call stacks.")
val YnoPatmatOpt = BooleanSetting("-Yno-patmat-opt", "disable all pattern matching optimizations.")
Expand Down
2 changes: 1 addition & 1 deletion compiler/src/dotty/tools/dotc/core/Annotations.scala
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ object Annotations {

private def resolveConstructor(atp: Type, args:List[Tree])(implicit ctx: Context): Tree = {
val targs = atp.argTypes
tpd.applyOverloaded(New(atp withoutArgs targs), nme.CONSTRUCTOR, args, targs, atp, isAnnotConstructor = true)
tpd.applyOverloaded(New(atp.typeConstructor), nme.CONSTRUCTOR, args, targs, atp, isAnnotConstructor = true)
}

def applyResolve(atp: Type, args: List[Tree])(implicit ctx: Context): Annotation = {
Expand Down
42 changes: 33 additions & 9 deletions compiler/src/dotty/tools/dotc/core/CheckRealizable.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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}")

Expand Down Expand Up @@ -89,18 +95,36 @@ 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
* they have good 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) =>
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,
Expand Down
26 changes: 21 additions & 5 deletions compiler/src/dotty/tools/dotc/core/ConstraintHandling.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -194,9 +194,15 @@ trait ConstraintHandling {
final def approximation(param: TypeParamRef, fromBelow: Boolean): Type = {
val avoidParam = new TypeMap {
override def stopAtStatic = true
def avoidInArg(arg: Type, formal: TypeParamInfo): 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.zipWithConserve(tycon.typeParams)(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.
Expand Down Expand Up @@ -306,7 +312,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
Expand All @@ -318,7 +329,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)
Expand Down Expand Up @@ -376,7 +387,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)
}

/** Drop all constrained parameters that occur at the toplevel in `bound` and
* handle them by `addLess` calls.
Expand Down
Loading