Skip to content
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

Direct representation of higher-kinded types #1343

Merged
merged 92 commits into from
Jul 15, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
92 commits
Select commit Hold shift + click to select a range
5866d0d
Allow refinements of new types
odersky May 24, 2016
d30f441
Allow general recursion in refined types.
odersky Jun 29, 2016
5d03186
Better printing of skolems
odersky May 26, 2016
cdb4a1c
New type lambda scheme for hk types
odersky Jun 29, 2016
850dc6f
Introduce recursive types
odersky Jun 29, 2016
af43d32
Abstract type parameters out from type symbols
odersky Jun 29, 2016
aa7f66d
Disable checkInst in RecType
odersky Jun 29, 2016
08a0ea6
Add printing of type lambda trees
odersky Jun 29, 2016
178e90e
Remove special case in parser
odersky May 27, 2016
4bf43f8
Turn on new hk scheme
odersky Jun 29, 2016
5daae27
Multiple fixes
odersky Jun 29, 2016
e56bd1f
Beta-reduce when simplifying
odersky Jun 2, 2016
e61b80a
Refinement of cycle avoidance
odersky Jun 2, 2016
a7d61c0
Make etaExpandIfHk work for non-symbol type params
odersky Jun 2, 2016
d0f82a5
Don't map info of SkolemTypes in type maps
odersky Jun 3, 2016
c136af1
Fixes to BetaReduce and asMemberOf; add a second betaReduce
odersky Jun 29, 2016
ae1f248
Normalize RecTypes on creation to avoid cycles.
odersky Jun 4, 2016
939d9da
Add a second betaReduce
odersky Jun 4, 2016
c35f817
Adapt widenForMatchSelector to new HK scheme
odersky Jun 5, 2016
e36a36a
Fix typeParams for abstract types under completion
odersky Jun 5, 2016
6a7e466
Avoid accidental creation of hk types
odersky Jun 29, 2016
8e84fb0
Eta-expand unapplied types that have type parameters
odersky Jun 29, 2016
68e73e8
Restrict betaReduce to hk applications
odersky Jun 29, 2016
463e99a
Optionally, check kinds match for & and |
odersky Jun 7, 2016
0a5f839
Avoid infinite recursion when comparing recursive types.
odersky Jun 29, 2016
31af865
Fix condition for lambda abstracting in Namer
odersky Jun 29, 2016
5041e93
Make TypeAccumulators follow LazyRefs
odersky Jun 7, 2016
f1bf78b
Avoid creating dependent function types for closures
odersky Jun 8, 2016
830b724
Change tests
odersky Jun 29, 2016
6414f3b
Deal with nested findMember calls over the same RecType
odersky Jun 9, 2016
e749d83
Various tweaks
odersky Jun 29, 2016
d1f809f
Remove old hk scheme
odersky Jun 29, 2016
60d81f8
Start new, direct HK scheme
odersky Jun 29, 2016
3490e01
Make Constraint#bounds work for aliases
odersky Jun 14, 2016
f6efd99
Fix appliedTo and typeParams, and higher kinded subtyping tests
odersky Jun 29, 2016
97e84e6
Fix printing of type lambda trees and types
odersky Jun 18, 2016
73dd039
Various hk related fixes in types
odersky Jun 29, 2016
02ce995
Refactoring of PolyType and TypeLambda
odersky Jun 29, 2016
c28dd1b
Tweaks to appliedTo
odersky Jun 29, 2016
c1e27a0
Change underlying of HKApply
odersky Jun 29, 2016
98b466c
Ensure wildApprox maintains kinds
odersky Jun 20, 2016
0965e1a
Handle TypeLambdas in findMember
odersky Jun 20, 2016
65c26ba
Avoid cyclic errors when reading nsc.Global
odersky Jun 21, 2016
1e48758
Refactor handling of unpickled type params
odersky Jun 29, 2016
960ea75
Allow for HK types in widenForMatchSelector
odersky Jun 22, 2016
e0db04d
Drop bounds checking for type lambdas
odersky Jun 22, 2016
de5d8fe
Skip typeBounds when computing upperBound
odersky Jun 22, 2016
8805dd4
When comparing types revert eta-expansion as needed
odersky Jun 26, 2016
646bf97
Beta-reduce with wildcard arguments if this is safe.
odersky Jun 29, 2016
09f7ab1
Handle findMember for unreduced hk types.
odersky Jun 27, 2016
9a90e81
Handle WildcardType in liftToClasses
odersky Jun 29, 2016
dca1052
Don't make * types higher-kinded in avoid
odersky Jun 29, 2016
4093e13
Don't dealias when applying types
odersky Jun 29, 2016
bb59931
Fixes to hk comparisons
odersky Jun 29, 2016
dc5be65
Special case for TypeRefs in upperbound
odersky Jun 28, 2016
31ecad5
Drop assertion in TypeMap
odersky Jun 29, 2016
9d9965c
Fix parameter unpickling
odersky Jun 28, 2016
a23c1a4
Fixes for printing under -Ytest-pickler
odersky Jun 29, 2016
6bd7ba9
Remove refinement encoding of hk types
odersky Jun 29, 2016
ae360e9
Handle signatures over uninstantiated type variables
odersky Jun 29, 2016
6abde38
Get rid of BindingKind
odersky Jun 29, 2016
68abba1
Simplify appliedTo
odersky Jun 29, 2016
30e15ab
Cleanup of Signature matching
odersky Jun 30, 2016
b6a8bc7
Revert complications in asMemberOf
odersky Jun 30, 2016
32c0135
Refactorings of GenericTypes and underlying/upperbound
odersky Jun 30, 2016
34a068b
Drop Config.checkKinds
odersky Jun 30, 2016
beff8f8
Avoid orphan parameters in Constraint#replace
odersky Jul 2, 2016
eebb4b0
Fix bug in printing untyped New nodes.
odersky Jul 3, 2016
fd62c7b
Disallow higher-kinded types that simulate general existential types
odersky Jul 7, 2016
4693a78
Less eager removal of type parameters from constraint
odersky Jul 7, 2016
2ddb849
Unify aliases when taking a lub.
odersky Jul 4, 2016
c541ef9
Do the right thing for NoDenotation.mapInfo
odersky Jul 7, 2016
78b2672
Add a case where caching was missing.
odersky Jul 5, 2016
223705d
Refactor Typevar instantiation
odersky Jul 7, 2016
5e90215
Drop compareAliasedRefined
odersky Jul 8, 2016
540b38c
More tests
odersky Jul 9, 2016
a200695
Fix SI-2712
odersky Jul 11, 2016
6d7bc49
Address reviewers comments
odersky Jul 11, 2016
055726e
ExtractAPI: Do not miss value parameters of PolyTypes
smarter Jul 12, 2016
a6a142e
ExtractAPI: Add support for TypeLambdas
smarter Jul 12, 2016
1792c9e
ExtractAPI: Add support for RecType
smarter Jul 12, 2016
cdebd91
Allow definition of new types in refinements
odersky Jul 11, 2016
84a1a7a
Avoid dealiasing on type application
odersky Jul 12, 2016
c7f3b45
Drop restriction to 2nd order hk types
odersky Jul 12, 2016
7df0fa5
Enable test for fixed #1181: Typer should preserve aliases in TypeTrees
smarter Jul 12, 2016
1443fd4
Optimize hk comparisons
odersky Jul 12, 2016
f50cb20
Make rewritings of hk applications configurable
odersky Jul 13, 2016
0ff5354
Simplify variance computations
odersky Jul 13, 2016
18b3080
Allow hk parameters in lower bounds
odersky Jul 13, 2016
82fc27f
Fix bounds checking of hk applied typed
odersky Jul 14, 2016
a737b47
Add test case for hk bounds checking
odersky Jul 14, 2016
894c9fb
Bounds of type lambdas compare contravariantly
odersky Jul 15, 2016
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
object B {
val x: Int = A.f1[Any](1)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
object A {
def f1[T](x: Int): Int = 1
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
object A {
def f1[T](x: String): Int = 1
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
object A {
def f1[T](x: Int): String = ""
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
object A {
def f1[T <: Int](x: Int): Int = 1
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import sbt._
import Keys._

object DottyInjectedPlugin extends AutoPlugin {
override def requires = plugins.JvmPlugin
override def trigger = allRequirements

override val projectSettings = Seq(
scalaVersion := "0.1-SNAPSHOT",
scalaOrganization := "ch.epfl.lamp",
scalacOptions += "-language:Scala2",
scalaBinaryVersion := "2.11",
autoScalaLibrary := false,
libraryDependencies ++= Seq("org.scala-lang" % "scala-library" % "2.11.5"),
scalaCompilerBridgeSource := ("ch.epfl.lamp" % "dotty-bridge" % "0.1.1-SNAPSHOT" % "component").sources()
)
}
20 changes: 20 additions & 0 deletions bridge/src/sbt-test/source-dependencies/signature-change/test
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Case 1: parameter type changed
$ copy-file changes/A0.scala A.scala
> compile
$ copy-file changes/A1.scala A.scala
# Compilation of B.scala should fail because the signature of f changed
-> compile

# Case 2: return type changed
$ copy-file changes/A0.scala A.scala
> compile
$ copy-file changes/A2.scala A.scala
# Compilation of B.scala should fail because the signature of f changed
-> compile

# Case 3: type parameter bounds changed
$ copy-file changes/A0.scala A.scala
> compile
$ copy-file changes/A3.scala A.scala
# Compilation of B.scala should fail because the signature of f changed
-> compile
7 changes: 4 additions & 3 deletions docs/SyntaxSummary.txt
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ grammar.
ClassQualifier ::= `[' id `]'

Type ::= FunArgTypes `=>' Type Function(ts, t)
| HkTypeParamClause `->' Type TypeLambda(ps, t)
| InfixType
FunArgTypes ::= InfixType
| `(' [ FunArgType {`,' FunArgType } ] `)'
Expand Down Expand Up @@ -125,7 +126,6 @@ grammar.
TypeParamBounds ::= TypeBounds {`<%' Type} {`:' Type} ContextBounds(typeBounds, tps)

Expr ::= FunParams `=>' Expr Function(args, expr), Function(ValDef([implicit], id, TypeTree(), EmptyTree), expr)
| Expr1
FunParams ::= Bindings
| [`implicit'] id
| `_'
Expand Down Expand Up @@ -225,7 +225,8 @@ grammar.
TypTypeParam ::= {Annotation} id [HkTypeParamClause] TypeBounds

HkTypeParamClause ::= `[' HkTypeParam {`,' HkTypeParam} `]'
HkTypeParam ::= {Annotation} ['+' | `-'] (Id | `_') TypeBounds
HkTypeParam ::= {Annotation} ['+' | `-'] (Id[HkTypeParamClause] | `_')
TypeBounds

ClsParamClauses ::= {ClsParamClause} [[nl] `(' `implicit' ClsParams `)']
ClsParamClause ::= [nl] `(' [ClsParams] ')'
Expand Down Expand Up @@ -280,7 +281,7 @@ grammar.
DefDcl ::= DefSig [`:' Type] DefDef(_, name, tparams, vparamss, tpe, EmptyTree)
DefSig ::= id [DefTypeParamClause] DefParamClauses
TypeDcl ::= id [TypTypeParamClause] ['=' Type] TypeDefTree(_, name, tparams, tpt)
| id [HkParamClause] TypeBounds TypeDefTree(_, name, tparams, bounds)
| id [HkTypeParamClause] TypeBounds TypeDefTree(_, name, tparams, bounds)

Def ::= `val' PatDef
| `var' VarDef
Expand Down
2 changes: 1 addition & 1 deletion src/dotty/tools/dotc/ast/Desugar.scala
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ object desugar {
val relocate = new TypeMap {
val originalOwner = sym.owner
def apply(tp: Type) = tp match {
case tp: NamedType if tp.symbol.owner eq originalOwner =>
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
if (local.exists) (defctx.owner.thisType select local).dealias
Expand Down
16 changes: 16 additions & 0 deletions src/dotty/tools/dotc/ast/Trees.scala
Original file line number Diff line number Diff line change
Expand Up @@ -594,6 +594,12 @@ object Trees {
def forwardTo = tpt
}

/** [typeparams] -> tpt */
case class TypeLambdaTree[-T >: Untyped] private[ast] (tparams: List[TypeDef[T]], body: Tree[T])
extends TypTree[T] {
type ThisTree[-T >: Untyped] = TypeLambdaTree[T]
}

/** => T */
case class ByNameTypeTree[-T >: Untyped] private[ast] (result: Tree[T])
extends TypTree[T] {
Expand Down Expand Up @@ -851,6 +857,7 @@ object Trees {
type OrTypeTree = Trees.OrTypeTree[T]
type RefinedTypeTree = Trees.RefinedTypeTree[T]
type AppliedTypeTree = Trees.AppliedTypeTree[T]
type TypeLambdaTree = Trees.TypeLambdaTree[T]
type ByNameTypeTree = Trees.ByNameTypeTree[T]
type TypeBoundsTree = Trees.TypeBoundsTree[T]
type Bind = Trees.Bind[T]
Expand Down Expand Up @@ -1028,6 +1035,10 @@ object Trees {
case tree: AppliedTypeTree if (tpt eq tree.tpt) && (args eq tree.args) => tree
case _ => finalize(tree, untpd.AppliedTypeTree(tpt, args))
}
def TypeLambdaTree(tree: Tree)(tparams: List[TypeDef], body: Tree): TypeLambdaTree = tree match {
case tree: TypeLambdaTree if (tparams eq tree.tparams) && (body eq tree.body) => tree
case _ => finalize(tree, untpd.TypeLambdaTree(tparams, body))
}
def ByNameTypeTree(tree: Tree)(result: Tree): ByNameTypeTree = tree match {
case tree: ByNameTypeTree if result eq tree.result => tree
case _ => finalize(tree, untpd.ByNameTypeTree(result))
Expand Down Expand Up @@ -1160,6 +1171,8 @@ object Trees {
cpy.RefinedTypeTree(tree)(transform(tpt), transformSub(refinements))
case AppliedTypeTree(tpt, args) =>
cpy.AppliedTypeTree(tree)(transform(tpt), transform(args))
case TypeLambdaTree(tparams, body) =>
cpy.TypeLambdaTree(tree)(transformSub(tparams), transform(body))
case ByNameTypeTree(result) =>
cpy.ByNameTypeTree(tree)(transform(result))
case TypeBoundsTree(lo, hi) =>
Expand Down Expand Up @@ -1264,6 +1277,9 @@ object Trees {
this(this(x, tpt), refinements)
case AppliedTypeTree(tpt, args) =>
this(this(x, tpt), args)
case TypeLambdaTree(tparams, body) =>
implicit val ctx: Context = localCtx
this(this(x, tparams), body)
case ByNameTypeTree(result) =>
this(x, result)
case TypeBoundsTree(lo, hi) =>
Expand Down
2 changes: 1 addition & 1 deletion src/dotty/tools/dotc/ast/tpd.scala
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
private def ta(implicit ctx: Context) = ctx.typeAssigner

def Modifiers(sym: Symbol)(implicit ctx: Context): Modifiers = Modifiers(
sym.flags & ModifierFlags,
sym.flags & (if (sym.isType) ModifierFlags | VarianceFlags else ModifierFlags),
if (sym.privateWithin.exists) sym.privateWithin.asType.name else tpnme.EMPTY,
sym.annotations map (_.tree))

Expand Down
1 change: 1 addition & 0 deletions src/dotty/tools/dotc/ast/untpd.scala
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,7 @@ object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo {
def OrTypeTree(left: Tree, right: Tree): OrTypeTree = new OrTypeTree(left, right)
def RefinedTypeTree(tpt: Tree, refinements: List[Tree]): RefinedTypeTree = new RefinedTypeTree(tpt, refinements)
def AppliedTypeTree(tpt: Tree, args: List[Tree]): AppliedTypeTree = new AppliedTypeTree(tpt, args)
def TypeLambdaTree(tparams: List[TypeDef], body: Tree): TypeLambdaTree = new TypeLambdaTree(tparams, body)
def ByNameTypeTree(result: Tree): ByNameTypeTree = new ByNameTypeTree(result)
def TypeBoundsTree(lo: Tree, hi: Tree): TypeBoundsTree = new TypeBoundsTree(lo, hi)
def Bind(name: Name, body: Tree): Bind = new Bind(name, body)
Expand Down
12 changes: 9 additions & 3 deletions src/dotty/tools/dotc/config/Config.scala
Original file line number Diff line number Diff line change
Expand Up @@ -72,10 +72,9 @@ 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, $apply projections are checked that they apply to a
* higher-kinded type.
/** If this flag is set, higher-kinded applications are checked for validity
*/
final val checkProjections = false
final val checkHKApplications = false

/** The recursion depth for showing a summarized string */
final val summarizeDepth = 2
Expand All @@ -98,6 +97,13 @@ object Config {
*/
final val splitProjections = false

/** If this flag is on, always rewrite an application `S[Ts]` where `S` is an alias for
* `[Xs] -> U` to `[Xs := Ts]U`. If this flag is off, the rewriting is only done if `S` is a
* reference to an instantiated parameter. Turning this flag on was observed to
* give a ~6% speedup on the JUnit test suite.
*/
final val simplifyApplications = true

/** Initial size of superId table */
final val InitialSuperIdsSize = 4096

Expand Down
17 changes: 8 additions & 9 deletions src/dotty/tools/dotc/core/Constraint.scala
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ abstract class Constraint extends Showable {
type This <: Constraint

/** Does the constraint's domain contain the type parameters of `pt`? */
def contains(pt: PolyType): Boolean
def contains(pt: GenericType): Boolean

/** Does the constraint's domain contain the type parameter `param`? */
def contains(param: PolyParam): Boolean
Expand Down Expand Up @@ -79,7 +79,7 @@ abstract class Constraint extends Showable {
* satisfiability but will solved to give instances of
* type variables.
*/
def add(poly: PolyType, tvars: List[TypeVar])(implicit ctx: Context): This
def add(poly: GenericType, tvars: List[TypeVar])(implicit ctx: Context): This

/** A new constraint which is derived from this constraint by updating
* the entry for parameter `param` to `tp`.
Expand Down Expand Up @@ -117,18 +117,17 @@ abstract class Constraint extends Showable {
*/
def narrowBound(param: PolyParam, bound: Type, isUpper: Boolean)(implicit ctx: Context): This

/** Is entry associated with `pt` removable?
* @param removedParam The index of a parameter which is still present in the
* entry array, but is going to be removed at the same step,
* or -1 if no such parameter exists.
/** Is entry associated with `pt` removable? This is the case if
* all type parameters of the entry are associated with type variables
* which have their `inst` fields set.
*/
def isRemovable(pt: PolyType, removedParam: Int = -1): Boolean
def isRemovable(pt: GenericType): Boolean

/** A new constraint with all entries coming from `pt` removed. */
def remove(pt: PolyType)(implicit ctx: Context): This
def remove(pt: GenericType)(implicit ctx: Context): This

/** The polytypes constrained by this constraint */
def domainPolys: List[PolyType]
def domainPolys: List[GenericType]

/** The polytype parameters constrained by this constraint */
def domainParams: List[PolyParam]
Expand Down
110 changes: 102 additions & 8 deletions src/dotty/tools/dotc/core/ConstraintHandling.scala
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import Types._, Contexts._, Symbols._
import Decorators._
import config.Config
import config.Printers._
import TypeApplications.EtaExpansion
import collection.mutable

/** Methods for adding constraints and solving them.
Expand Down Expand Up @@ -34,6 +35,11 @@ trait ConstraintHandling {
/** If the constraint is frozen we cannot add new bounds to the constraint. */
protected var frozenConstraint = false

/** We are currently comparing lambdas. Used as a flag for
* optimization: when `false`, no need to do an expensive `pruneLambdaParams`
*/
protected var comparingLambdas = false

private def addOneBound(param: PolyParam, bound: Type, isUpper: Boolean): Boolean =
!constraint.contains(param) || {
def occursIn(bound: Type): Boolean = {
Expand Down Expand Up @@ -163,12 +169,64 @@ trait ConstraintHandling {
}
}
}
assert(constraint.contains(param))
val bound = if (fromBelow) constraint.fullLowerBound(param) else constraint.fullUpperBound(param)
val inst = avoidParam(bound)
typr.println(s"approx ${param.show}, from below = $fromBelow, bound = ${bound.show}, inst = ${inst.show}")
inst
}

/** The instance type of `param` in the current constraint (which contains `param`).
* If `fromBelow` is true, the instance type is the lub of the parameter's
* lower bounds; otherwise it is the glb of its upper bounds. However,
* a lower bound instantiation can be a singleton type only if the upper bound
* is also a singleton type.
*/
def instanceType(param: PolyParam, fromBelow: Boolean): Type = {
def upperBound = constraint.fullUpperBound(param)
def isSingleton(tp: Type): Boolean = tp match {
case tp: SingletonType => true
case AndType(tp1, tp2) => isSingleton(tp1) | isSingleton(tp2)
case OrType(tp1, tp2) => isSingleton(tp1) & isSingleton(tp2)
case _ => false
}
def isFullyDefined(tp: Type): Boolean = tp match {
case tp: TypeVar => tp.isInstantiated && isFullyDefined(tp.instanceOpt)
case tp: TypeProxy => isFullyDefined(tp.underlying)
case tp: AndOrType => isFullyDefined(tp.tp1) && isFullyDefined(tp.tp2)
case _ => true
}
def isOrType(tp: Type): Boolean = tp.stripTypeVar.dealias match {
case tp: OrType => true
case tp: RefinedOrRecType => isOrType(tp.parent)
case AndType(tp1, tp2) => isOrType(tp1) | isOrType(tp2)
case WildcardType(bounds: TypeBounds) => isOrType(bounds.hi)
case _ => false
}

// First, solve the constraint.
var inst = approximation(param, fromBelow)

// Then, approximate by (1.) - (3.) and simplify as follows.
// 1. If instance is from below and is a singleton type, yet
// upper bound is not a singleton type, widen the instance.
if (fromBelow && isSingleton(inst) && !isSingleton(upperBound))
inst = inst.widen

inst = inst.simplified

// 2. If instance is from below and is a fully-defined union type, yet upper bound
// is not a union type, approximate the union type from above by an intersection
// of all common base types.
if (fromBelow && isOrType(inst) && isFullyDefined(inst) && !isOrType(upperBound))
inst = inst.approximateUnion

// 3. If instance is from below, and upper bound has open named parameters
// make sure the instance has all named parameters of the bound.
if (fromBelow) inst = inst.widenToNamedTypeParams(param.namedTypeParams)
inst
}

/** Constraint `c1` subsumes constraint `c2`, if under `c2` as constraint we have
* for all poly params `p` defined in `c2` as `p >: L2 <: U2`:
*
Expand All @@ -193,9 +251,9 @@ trait ConstraintHandling {
}

/** The current bounds of type parameter `param` */
final def bounds(param: PolyParam): TypeBounds = constraint.entry(param) match {
case bounds: TypeBounds => bounds
case _ => param.binder.paramBounds(param.paramNum)
final def bounds(param: PolyParam): TypeBounds = {
val e = constraint.entry(param)
if (e.exists) e.bounds else param.binder.paramBounds(param.paramNum)
}

/** Add polytype `pt`, possibly with type variables `tvars`, to current constraint
Expand Down Expand Up @@ -236,6 +294,36 @@ trait ConstraintHandling {
checkPropagated(s"added $description") {
addConstraintInvocations += 1

/** When comparing lambdas we might get constraints such as
* `A <: X0` or `A = List[X0]` where `A` is a constrained parameter
* and `X0` is a lambda parameter. The constraint for `A` is not allowed
* to refer to such a lambda parameter because the lambda parameter is
* not visible where `A` is defined. Consequently, we need to
* approximate the bound so that the lambda parameter does not appear in it.
* If `tp` is an upper bound, we need to approximate with something smaller,
* otherwise something larger.
* Test case in pos/i94-nada.scala. This test crashes with an illegal instance
* error in Test2 when the rest of the SI-2712 fix is applied but `pruneLambdaParams` is
* missing.
*/
def pruneLambdaParams(tp: Type) =
if (comparingLambdas && param.binder.isInstanceOf[PolyType]) {
val approx = new ApproximatingTypeMap {
def apply(t: Type): Type = t match {
case t @ PolyParam(tl: TypeLambda, n) =>
val effectiveVariance = if (fromBelow) -variance else variance
val bounds = tl.paramBounds(n)
if (effectiveVariance > 0) bounds.lo
else if (effectiveVariance < 0) bounds.hi
else NoType
case _ =>
mapOver(t)
}
}
approx(tp)
}
else tp

def addParamBound(bound: PolyParam) =
if (fromBelow) addLess(bound, param) else addLess(param, bound)

Expand Down Expand Up @@ -281,12 +369,18 @@ trait ConstraintHandling {
else NoType
case bound: TypeVar if constraint contains bound.origin =>
prune(bound.underlying)
case bound: PolyParam if constraint contains bound =>
if (!addParamBound(bound)) NoType
else if (fromBelow) defn.NothingType
else defn.AnyType
case bound: PolyParam =>
constraint.entry(bound) match {
case NoType => pruneLambdaParams(bound)
case _: TypeBounds =>
if (!addParamBound(bound)) NoType
else if (fromBelow) defn.NothingType
else defn.AnyType
case inst =>
prune(inst)
}
case _ =>
bound
pruneLambdaParams(bound)
}

try bound match {
Expand Down
Loading