summaryrefslogtreecommitdiff
path: root/src/compiler
diff options
context:
space:
mode:
authorMartin Odersky <odersky@gmail.com>2006-10-19 20:52:30 +0000
committerMartin Odersky <odersky@gmail.com>2006-10-19 20:52:30 +0000
commitbcac3c45b280584f740c94b2ccd77f7812adf672 (patch)
treebe08675b14e33b8b78c828e0626e8920420eabd5 /src/compiler
parent458d3d10cfcd7dd44cb1d6b02de7ea0fdbe6b955 (diff)
downloadscala-bcac3c45b280584f740c94b2ccd77f7812adf672.tar.gz
scala-bcac3c45b280584f740c94b2ccd77f7812adf672.tar.bz2
scala-bcac3c45b280584f740c94b2ccd77f7812adf672.zip
added support for typed patterns
Diffstat (limited to 'src/compiler')
-rw-r--r--src/compiler/scala/tools/nsc/CompilationUnits.scala4
-rw-r--r--src/compiler/scala/tools/nsc/Global.scala6
-rw-r--r--src/compiler/scala/tools/nsc/Settings.scala1
-rw-r--r--src/compiler/scala/tools/nsc/ast/TreeInfo.scala22
-rw-r--r--src/compiler/scala/tools/nsc/ast/TreePrinters.scala1
-rw-r--r--src/compiler/scala/tools/nsc/ast/Trees.scala5
-rw-r--r--src/compiler/scala/tools/nsc/ast/parser/Parsers.scala99
-rw-r--r--src/compiler/scala/tools/nsc/symtab/Types.scala302
-rw-r--r--src/compiler/scala/tools/nsc/transform/UnCurry.scala2
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Contexts.scala10
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Infer.scala169
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/RefChecks.scala2
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Typers.scala71
13 files changed, 378 insertions, 316 deletions
diff --git a/src/compiler/scala/tools/nsc/CompilationUnits.scala b/src/compiler/scala/tools/nsc/CompilationUnits.scala
index 7300549484..24f4cf7497 100644
--- a/src/compiler/scala/tools/nsc/CompilationUnits.scala
+++ b/src/compiler/scala/tools/nsc/CompilationUnits.scala
@@ -34,6 +34,10 @@ trait CompilationUnits requires Global {
def warning(pos: int, msg: String) = reporter.warning(position(pos), msg)
+ def deprecationWarning(pos: int, msg: String) =
+ if (settings.deprecation.value) reporter.warning(position(pos), msg)
+ else currentRun.deprecationWarnings = true
+
override def toString() = source.toString()
def clear() = {
diff --git a/src/compiler/scala/tools/nsc/Global.scala b/src/compiler/scala/tools/nsc/Global.scala
index 01d1ed4eac..5907c217a7 100644
--- a/src/compiler/scala/tools/nsc/Global.scala
+++ b/src/compiler/scala/tools/nsc/Global.scala
@@ -386,6 +386,9 @@ class Global(var settings: Settings, var reporter: Reporter) extends SymbolTable
// that's why it is placed here.
icodes.init
+ /** Deprecation warnings occurred */
+ var deprecationWarnings: boolean = false
+
private var p: Phase = firstPhase
private var stopped = false
for (val pd <- phaseDescriptors) {
@@ -489,6 +492,9 @@ class Global(var settings: Settings, var reporter: Reporter) extends SymbolTable
if (reporter.errors == 0) {
assert(stopped || symData.isEmpty, symData.elements.toList)
+ if (deprecationWarnings) {
+ warning("there were deprecation warnings; re-run with -deprecation for details")
+ }
} else {
for (val Pair(sym, file) <- symSource.elements) {
sym.reset(new loaders.SourcefileLoader(file))
diff --git a/src/compiler/scala/tools/nsc/Settings.scala b/src/compiler/scala/tools/nsc/Settings.scala
index 5437f70172..54d955b275 100644
--- a/src/compiler/scala/tools/nsc/Settings.scala
+++ b/src/compiler/scala/tools/nsc/Settings.scala
@@ -91,6 +91,7 @@ class Settings(error: String => unit) {
val target = ChoiceSetting ("-target", "Specify which backend to use", List("jvm-1.5", "jvm-1.4", "msil", "cldc"), "jvm-1.4")
val migrate = BooleanSetting("-migrate", "Assist in migrating from Scala version 1.0")
val debug = new BooleanSetting("-debug", "Output debugging messages") { override def hiddenToIDE = true }
+ val deprecation = BooleanSetting ("-deprecation", "enable detailed deprecatation warnings")
val statistics = new BooleanSetting("-statistics", "Print compiler statistics") { override def hiddenToIDE = true }
val explaintypes = BooleanSetting("-explaintypes", "Explain type errors in more detail")
val resident = new BooleanSetting("-resident", "Compiler stays resident, files to compile are read from standard input") { override def hiddenToIDE = true }
diff --git a/src/compiler/scala/tools/nsc/ast/TreeInfo.scala b/src/compiler/scala/tools/nsc/ast/TreeInfo.scala
index e1a63d699e..4ac7646e4a 100644
--- a/src/compiler/scala/tools/nsc/ast/TreeInfo.scala
+++ b/src/compiler/scala/tools/nsc/ast/TreeInfo.scala
@@ -7,6 +7,7 @@
package scala.tools.nsc.ast
import symtab.Flags._
+import util.{Set, HashSet}
/** This class ...
*
@@ -136,13 +137,24 @@ abstract class TreeInfo {
def isLeftAssoc(operator: Name): boolean =
operator.length > 0 && operator(operator.length - 1) != ':';
+ private val reserved = new HashSet[Name]
+ reserved addEntry nme.false_
+ reserved addEntry nme.true_
+ reserved addEntry nme.null_
+ reserved addEntry newTypeName("byte")
+ reserved addEntry newTypeName("char")
+ reserved addEntry newTypeName("short")
+ reserved addEntry newTypeName("int")
+ reserved addEntry newTypeName("long")
+ reserved addEntry newTypeName("float")
+ reserved addEntry newTypeName("double")
+ reserved addEntry newTypeName("boolean")
+ reserved addEntry newTypeName("unit")
+
/** Is name a variable name? */
def isVariableName(name: Name): boolean = {
- val first = name(0);
- ((('a' <= first && first <= 'z') || first == '_')
- && name != nme.false_
- && name != nme.true_
- && name != nme.null_)
+ val first = name(0)
+ (('a' <= first && first <= 'z') || first == '_') && !(reserved contains name)
}
/** Is tree a this node which belongs to `enclClass'? */
diff --git a/src/compiler/scala/tools/nsc/ast/TreePrinters.scala b/src/compiler/scala/tools/nsc/ast/TreePrinters.scala
index 9f9ce71c7e..f63a1a3991 100644
--- a/src/compiler/scala/tools/nsc/ast/TreePrinters.scala
+++ b/src/compiler/scala/tools/nsc/ast/TreePrinters.scala
@@ -280,7 +280,6 @@ abstract class TreePrinters {
print("this")
case Select(qual @ New(tpe), name) =>
- assert(tree.symbol == null || tree.symbol.isConstructor || phase.prev.name == "parser")
print(qual)
case Select(qualifier, name) =>
diff --git a/src/compiler/scala/tools/nsc/ast/Trees.scala b/src/compiler/scala/tools/nsc/ast/Trees.scala
index 817ad2d451..4a64067f8a 100644
--- a/src/compiler/scala/tools/nsc/ast/Trees.scala
+++ b/src/compiler/scala/tools/nsc/ast/Trees.scala
@@ -411,7 +411,10 @@ trait Trees requires Global {
* @param body
*/
case class Bind(name: Name, body: Tree)
- extends DefTree
+ extends DefTree {
+ override def isTerm = name.isTermName
+ override def isType = name.isTypeName
+ }
def Bind(sym: Symbol, body: Tree): Bind =
Bind(sym.name, body) setSymbol sym
diff --git a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala
index 2cfad833a7..2d7ac53c3a 100644
--- a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala
+++ b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala
@@ -502,7 +502,7 @@ trait Parsers requires SyntaxAnalyzer {
if (in.token == COLON | in.token == REQUIRES) {
if (in.token == COLON)
warning("`:' has been deprecated; use `requires' instead")
- in.nextToken(); simpleType()
+ in.nextToken(); simpleType(false)
}
else TypeTree()
@@ -546,7 +546,7 @@ trait Parsers requires SyntaxAnalyzer {
}
}
} else {
- type1()
+ type1(false)
}
if (in.token == ARROW) atPos(in.skipToken()) {
makeFunctionTypeTree(List(t), typ()) }
@@ -554,29 +554,33 @@ trait Parsers requires SyntaxAnalyzer {
}
/** Type1 ::= SimpleType {with SimpleType} [Refinement]
+ * TypePattern1 ::= SimpleTypePattern [TypePatternArgs]
*/
- def type1(): Tree = {
+ def type1(isPattern: boolean): Tree = {
val pos = in.currentPos
- var ts = new ListBuffer[Tree] + simpleType()
- while (in.token == WITH) {
- in.nextToken(); ts += simpleType()
+ var ts = new ListBuffer[Tree] + simpleType(isPattern)
+ while (in.token == WITH && !isPattern) {
+ in.nextToken(); ts += simpleType(isPattern)
}
atPos(pos) {
- if (in.token == LBRACE) CompoundTypeTree(Template(ts.toList, refinement()))
+ if (in.token == LBRACE && !isPattern) CompoundTypeTree(Template(ts.toList, refinement()))
else makeIntersectionTypeTree(ts.toList)
}
}
- /** SimpleType ::= SimpleType TypeArgs
- * | SimpleType `#' Id
- * | StableId
- * | Path `.' type
- * | `(' Type `)'
+ /** SimpleType ::= SimpleType TypeArgs
+ * | SimpleType `#' Id
+ * | StableId
+ * | Path `.' type
+ * | `(' Type `)'
+ * SimpleTypePattern ::= SimpleTypePattern "#" Id
+ * | StableId
+ * | Path `.' type)
*/
- def simpleType(): Tree = {
+ def simpleType(isPattern: boolean): Tree = {
val pos = in.currentPos
var t: Tree =
- if (in.token == LPAREN) {
+ if (in.token == LPAREN && !isPattern) {
in.nextToken()
val t = typ()
accept(RPAREN)
@@ -596,35 +600,42 @@ trait Parsers requires SyntaxAnalyzer {
SelectFromTypeTree(t, ident().toTypeName)
}
else if (in.token == LBRACKET)
- t = atPos(pos) { AppliedTypeTree(t, typeArgs()) }
+ t = atPos(pos) { AppliedTypeTree(t, typeArgs(isPattern)) }
else
return t
}
null; //dummy
}
- /** TypeArgs ::= `[' TypeArg {`,' TypeArg} `]'
+ /** TypeArgs ::= `[' TypeArg {`,' TypeArg} `]'
+ * TypePatternArgs ::= '[' TypePatternArg {`,' TypePatternArg} `]'
*/
- def typeArgs(): List[Tree] = {
+ def typeArgs(isPattern: boolean): List[Tree] = {
accept(LBRACKET)
- val ts = new ListBuffer[Tree] + typeArg()
+ val ts = new ListBuffer[Tree] + typeArg(isPattern)
while (in.token == COMMA) {
in.nextToken()
- ts += typeArg()
+ ts += typeArg(isPattern)
}
accept(RBRACKET)
ts.toList
}
- /** TypeArg ::= Type
- * | `_' TypeBounds
+ /** TypeArg ::= Type
+ * TypePatternArg ::= varid
+ * | `_'
+ * | Type // for array elements only!
*/
- def typeArg(): Tree =
- if (in.token == USCORE && settings.Xexperimental.value)
- atPos(in.skipToken()) {
- WildcardTypeTree(bound(SUPERTYPE, nme.Nothing), bound(SUBTYPE, nme.Any))
+ def typeArg(isPattern: boolean): Tree =
+ if (isPattern) {
+ if (in.token == USCORE)
+ atPos(in.skipToken()) { Bind(nme.WILDCARD.toTypeName, EmptyTree) }
+ else if (in.token == IDENTIFIER && treeInfo.isVariableName(in.name.toTypeName))
+ atPos(in.currentPos) { Bind(ident().toTypeName, EmptyTree) }
+ else {
+ typ()
}
- else typ()
+ } else typ()
//////// EXPRESSIONS ////////////////////////////////////////////////////////
@@ -813,7 +824,7 @@ trait Parsers requires SyntaxAnalyzer {
syntaxError(in.currentPos, "`*' expected", true)
}
} else {
- t = atPos(pos) { Typed(t, if (isInBlock) type1() else typ()) }
+ t = atPos(pos) { Typed(t, if (isInBlock) type1(false) else typ()) }
if (isInBlock && in.token == COMMA) {
val vdefs = new ListBuffer[ValDef]
while (in.token == COMMA) {
@@ -946,14 +957,14 @@ trait Parsers requires SyntaxAnalyzer {
t = blockExpr()
case NEW =>
t = atPos(in.skipToken()) {
- val parents = new ListBuffer[Tree] + simpleType()
+ val parents = new ListBuffer[Tree] + simpleType(false)
val argss = new ListBuffer[List[Tree]]
if (in.token == LPAREN)
do { argss += argumentExprs() } while (in.token == LPAREN)
else argss += List()
while (in.token == WITH) {
in.nextToken()
- parents += simpleType()
+ parents += simpleType(false)
}
val stats = if (in.token == LBRACE) templateBody() else List()
makeNew(parents.toList, stats, argss.toList)
@@ -976,7 +987,7 @@ trait Parsers requires SyntaxAnalyzer {
case LBRACKET =>
t match {
case Ident(_) | Select(_, _) =>
- t = atPos(in.currentPos) { TypeApply(t, typeArgs()) }
+ t = atPos(in.currentPos) { TypeApply(t, typeArgs(false)) }
case _ =>
return t
}
@@ -1093,11 +1104,11 @@ trait Parsers requires SyntaxAnalyzer {
def pattern(): Tree = pattern(false)
- /** Pattern1 ::= varid `:' Type1
- * | `_' `:' Type1
+ /** Pattern1 ::= varid `:' TypePattern1
+ * | `_' `:' TypePattern1
* | Pattern2
- * SeqPattern1 ::= varid `:' Type1
- * | `_' `:' Type1
+ * SeqPattern1 ::= varid `:' TypePattern1
+ * | `_' `:' TypePattern1
* | [SeqPattern2]
*/
def pattern1(seqOK: boolean): Tree = {
@@ -1107,7 +1118,7 @@ trait Parsers requires SyntaxAnalyzer {
val p = pattern2(seqOK)
p match {
case Ident(name) if (treeInfo.isVarPattern(p) && in.token == COLON) =>
- atPos(in.skipToken()) { Typed(p, type1()) }
+ atPos(in.skipToken()) { Typed(p, type1(true)) }
case _ =>
p
}
@@ -1173,7 +1184,7 @@ trait Parsers requires SyntaxAnalyzer {
* | `_'
* | literal
* | `<' xLiteralPattern
- * | StableId [ `(' Patterns `)' ]
+ * | StableId [TypePatternArgs] `(' Patterns `)' ]
* | `(' Patterns `)'
*/
def simplePattern(seqOK: boolean): Tree = in.token match {
@@ -1188,6 +1199,16 @@ trait Parsers requires SyntaxAnalyzer {
}
case _ =>
}
+/* not yet
+ if (in.token == LBRACKET)
+ atPos(in.currentPos) {
+ val ts = typeArgs(true)
+ accept(LPAREN)
+ val ps = if (in.token == RPAREN) List() else patterns()
+ accept(RPAREN)
+ Apply(TypeApply(convertToTypeId(t), ts), ps)
+ }
+ else */
if (in.token == LPAREN) {
atPos(in.skipToken()) {
val ps = if (in.token == RPAREN) List() else patterns()
@@ -1773,7 +1794,7 @@ trait Parsers requires SyntaxAnalyzer {
val argss = new ListBuffer[List[Tree]]
if (in.token == EXTENDS) {
in.nextToken()
- val parent = simpleType()
+ val parent = simpleType(false)
// System.err.println("classTempl: " + parent)
parents += parent
if (in.token == LPAREN)
@@ -1781,7 +1802,7 @@ trait Parsers requires SyntaxAnalyzer {
else argss += List()
while (in.token == WITH) {
in.nextToken()
- parents += simpleType()
+ parents += simpleType(false)
}
} else {
if (in.token == WITH && settings.migrate.value)
@@ -1924,7 +1945,7 @@ trait Parsers requires SyntaxAnalyzer {
val pos = in.currentPos
var t: Tree = convertToTypeId(stableId())
if (in.token == LBRACKET)
- t = atPos(in.currentPos)(AppliedTypeTree(t, typeArgs()))
+ t = atPos(in.currentPos)(AppliedTypeTree(t, typeArgs(false)))
val args = if (in.token == LPAREN) argumentExprs() else List()
val nameValuePairs: List[Tree] = if (in.token == LBRACE) {
in.nextToken()
diff --git a/src/compiler/scala/tools/nsc/symtab/Types.scala b/src/compiler/scala/tools/nsc/symtab/Types.scala
index 6005f24765..9fdf1db895 100644
--- a/src/compiler/scala/tools/nsc/symtab/Types.scala
+++ b/src/compiler/scala/tools/nsc/symtab/Types.scala
@@ -45,10 +45,7 @@ trait Types requires SymbolTable {
var subtypeMillis = 0l
private var explainSwitch = false
-
- /** A varaince value that expresses that no type approximations are allowed
- */
- private final val NOAPPROX = -2
+ private var checkMalformedSwitch = true
val emptyTypeArray = new Array[Type](0)
@@ -92,16 +89,6 @@ trait Types requires SymbolTable {
*/
def bounds: TypeBounds = TypeBounds(this, this)
- /** For a TypeBounds type, its lower bound;
- * for all other types, the type itself
- */
- def lowerBound: Type = this
-
- /** For a TypeBounds type, its upper bound;
- * for all other types, the type itself
- */
- def upperBound: Type = this
-
/** For a class or intersection type, its parents.
* For a TypeBounds type, the parents of its hi bound.
* inherited by typerefs, singleton types, and refinement types,
@@ -238,7 +225,7 @@ trait Types requires SymbolTable {
}
*/
case _ =>
- //System.out.println("" + this + ".memberType(" + sym +":" + sym.tpe +")");//DEBUG
+ //System.out.println("" + this.widen + ".memberType(" + sym +":" + sym.tpe +")");//DEBUG
sym.tpe.asSeenFrom(this, sym.owner)
}
}
@@ -288,11 +275,6 @@ trait Types requires SymbolTable {
else isSameType(this, that))
);
- /** Does this type contain that type? This is true if the two types are the same wrt <:<,
- * or this type is a TypeBounds which contains that type
- */
- def containsType(that: Type) = this <:< that && that <:< this
-
/** Does this type implement symbol <code>sym</code> with same or stronger type?
*/
def specializes(sym: Symbol): boolean =
@@ -435,6 +417,8 @@ trait Types requires SymbolTable {
var excluded = excludedFlags | DEFERRED
var self: Type = null
var continue = true
+ var savedCheckMalformedSwitch = checkMalformedSwitch
+ checkMalformedSwitch = false
while (continue) {
continue = false
var bcs = baseClasses
@@ -449,6 +433,7 @@ trait Types requires SymbolTable {
val excl = sym.getFlag(excluded)
if (excl == 0) {
if (name.isTypeName || stableOnly) {
+ checkMalformedSwitch = savedCheckMalformedSwitch
if (util.Statistics.enabled)
findMemberMillis = findMemberMillis + System.currentTimeMillis() - startTime
return sym
@@ -486,6 +471,7 @@ trait Types requires SymbolTable {
} // while (!bcs.isEmpty)
excluded = excludedFlags
} // while (continue)
+ checkMalformedSwitch = savedCheckMalformedSwitch
if (util.Statistics.enabled)
findMemberMillis = findMemberMillis + System.currentTimeMillis() - startTime
if (members == null) {
@@ -561,7 +547,7 @@ trait Types requires SymbolTable {
}
case class BoundedWildcardType(override val bounds: TypeBounds) extends Type {
- override def toString(): String = "? " + bounds.boundsString
+ override def toString(): String = "?" + bounds
}
/** An object representing a non-existing type */
@@ -660,12 +646,9 @@ trait Types requires SymbolTable {
override val isTrivial: boolean = lo.isTrivial && hi.isTrivial
def supertype: Type = hi
override def bounds: TypeBounds = this
- override def lowerBound: Type = lo
- override def upperBound: Type = hi
- override def containsType(that: Type) = that <:< this || lo <:< that && that <:< hi
+ def containsType(that: Type) = that <:< this || lo <:< that && that <:< hi;
// override def isNullable: boolean = AllRefClass.tpe <:< lo;
- override def toString = "_ "+boundsString
- def boundsString = ">: "+lo+" <: "+ hi
+ override def toString() = ">: " + lo + " <: " + hi
}
/** A common base class for intersection types and class types
@@ -734,7 +717,11 @@ trait Types requires SymbolTable {
case RefinedType(parents, decls) =>
assert(decls.isEmpty)
//Console.println("compute closure of "+this+" => glb("+parents+")")
- closureCache(j) = glbNoRefinement(parents)
+ closureCache(j) = mergePrefixAndArgs(parents, -1) match {
+ case Some(tp0) => tp0
+ case None => throw new MalformedClosure(parents)
+ }
+ assert(!closureCache(j).isInstanceOf[RefinedType], closureCache(j))
case _ =>
}
j = j + 1
@@ -871,7 +858,7 @@ trait Types requires SymbolTable {
* @param args ...
*/
abstract case class TypeRef(pre: Type, sym: Symbol, args: List[Type]) extends Type {
- assert(!sym.isAbstractType || pre.isStable || pre.isError)
+ assert(!checkMalformedSwitch || !sym.isAbstractType || pre.isStable || pre.isError)
assert(!pre.isInstanceOf[ClassInfoType], this)
assert(!sym.isTypeParameterOrSkolem || pre == NoPrefix, this)
@@ -1116,33 +1103,21 @@ trait Types requires SymbolTable {
def ThisType(sym: Symbol): Type =
if (phase.erasedTypes) sym.tpe else unique(new ThisType(sym) with UniqueType)
- /** A creator of type approximations, depending on variance
- */
- def typeApproximation(variance: int, lo: Type, hi: Type, pre: Type, sym: Symbol) = variance match {
- case 0 => TypeBounds(lo, hi)
- case 1 => hi
- case -1 => lo
- case NOAPPROX => throw new MalformedType(pre, sym.name.toString)
- }
-
/** The canonical creator for single-types */
- def singleType(pre: Type, sym: Symbol): Type = singleType(pre, sym, NOAPPROX)
-
- /** The creator for single-types or their approximations */
- def singleType(pre: Type, sym: Symbol, variance: int): Type =
+ def singleType(pre: Type, sym: Symbol): Type = {
if (phase.erasedTypes)
sym.tpe.resultType
+ else if (checkMalformedSwitch && !pre.isStable && !pre.isError)
+ throw new MalformedType(pre, sym.name.toString())
else if (sym.isRootPackage)
ThisType(RootClass)
else {
var sym1 = rebind(pre, sym)
val pre1 = removeSuper(pre, sym1)
if (pre1 ne pre) sym1 = rebind(pre1, sym1)
- if (!pre1.isStable && !pre1.isError)
- typeApproximation(variance, AllClass.tpe, pre.memberType(sym).resultType, pre, sym)
- else
- unique(new SingleType(pre1, sym1) with UniqueType)
+ unique(new SingleType(pre1, sym1) with UniqueType)
}
+ }
/** The canonical creator for super-types */
def SuperType(thistp: Type, supertp: Type): Type =
@@ -1174,6 +1149,20 @@ trait Types requires SymbolTable {
def refinedType(parents: List[Type], owner: Symbol): Type =
refinedType(parents, owner, newScope)
+ def copyRefinedType(original: RefinedType, parents: List[Type], decls: Scope) =
+ if ((parents eq original.parents) && (decls eq original.decls)) original
+ else {
+ val result = refinedType(parents, original.symbol.owner)
+ val syms1 = decls.toList
+ for (val sym <- syms1)
+ result.decls.enter(sym.cloneSymbol(result.symbol))
+ val syms2 = result.decls.toList
+ val resultThis = result.symbol.thisType
+ for (val sym <- syms2)
+ sym.setInfo(sym.info.substSym(syms1, syms2).substThis(original.symbol, resultThis))
+ result
+ }
+
/** the canonical creator for a constant type */
def ConstantType(value: Constant): ConstantType =
unique(new ConstantType(value) with UniqueType)
@@ -1185,11 +1174,10 @@ trait Types requires SymbolTable {
* @param args ...
* @return ...
*/
- def typeRef(pre: Type, sym: Symbol, args: List[Type]): Type = typeRef(pre, sym, args, NOAPPROX)
-
- /** The creator for typerefs or their approximations */
- def typeRef(pre: Type, sym: Symbol, args: List[Type], variance: int): Type = {
+ def typeRef(pre: Type, sym: Symbol, args: List[Type]): Type = {
var sym1 = if (sym.isAbstractType) rebind(pre, sym) else sym
+ if (checkMalformedSwitch && sym1.isAbstractType && !pre.isStable && !pre.isError)
+ throw new MalformedType(pre, sym.nameString)
if (sym1.isAliasType && sym1.info.typeParams.length == args.length) {
// note: we require that object is initialized,
// that's why we use info.typeParams instead of typeParams.
@@ -1203,13 +1191,7 @@ trait Types requires SymbolTable {
val pre1 = removeSuper(pre, sym1)
if (pre1 ne pre) {
if (sym1.isAbstractType) sym1 = rebind(pre1, sym1)
- typeRef(pre1, sym1, args, variance)
- } else if (sym1.isAbstractType && !pre.isStable && !pre.isError) {
- val lo = sym.info.bounds.lo
- var hi = sym.info.bounds.hi
- if (hi contains sym) hi = AnyClass.tpe // this is crude; we should try to refine this!
- def transform(tp: Type): Type = tp.asSeenFrom(pre, sym.owner).subst(sym.typeParams, args)
- typeApproximation(variance, transform(lo), transform(hi), pre, sym1)
+ typeRef(pre1, sym1, args)
} else {
rawTypeRef(pre, sym1, args)
}
@@ -1316,19 +1298,6 @@ trait Types requires SymbolTable {
abstract class TypeMap extends Function1[Type, Type] {
// deferred inherited: def apply(tp: Type): Type
- var variance = 1
-
- private def cloneDecls(result: Type, tp: Type, decls: Scope): Type = {
- val syms1 = decls.toList
- for (val sym <- syms1)
- result.decls.enter(sym.cloneSymbol(result.symbol));
- val syms2 = result.decls.toList
- val resultThis = result.symbol.thisType
- for (val sym <- syms2)
- sym.setInfo(sym.info.substSym(syms1, syms2).substThis(tp.symbol, resultThis));
- result
- }
-
/** Map this function over given type */
def mapOver(tp: Type): Type = tp match {
case ErrorType => tp
@@ -1340,11 +1309,9 @@ trait Types requires SymbolTable {
case SingleType(pre, sym) =>
if (sym.isPackageClass) tp // short path
else {
- val v = variance; variance = 0
val pre1 = this(pre)
- variance = v
if (pre1 eq pre) tp
- else singleType(pre1, sym, variance)
+ else singleType(pre1, sym)
}
case SuperType(thistp, supertp) =>
val thistp1 = this(thistp)
@@ -1353,31 +1320,22 @@ trait Types requires SymbolTable {
else SuperType(thistp1, supertp1)
case TypeRef(pre, sym, args) =>
val pre1 = this(pre)
- //val args1 = List.mapConserve(args)(this)
- val args1 = if (args.isEmpty) args
- else {
- val tparams = sym.typeParams
- if (tparams.isEmpty) args
- else mapOverArgs(args, tparams)
- }
+ val args1 = List.mapConserve(args)(this)
if ((pre1 eq pre) && (args1 eq args)) tp
- else typeRef(pre1, sym, args1, variance)
+ else typeRef(pre1, sym, args1)
case TypeBounds(lo, hi) =>
- variance = -variance
val lo1 = this(lo)
- variance = -variance
val hi1 = this(hi)
if ((lo1 eq lo) && (hi1 eq hi)) tp
else TypeBounds(lo1, hi1)
- case BoundedWildcardType(bounds) => //todo: merge WildcardType and BoundedWildcardType?
+ case BoundedWildcardType(bounds) =>
val bounds1 = this(bounds)
if (bounds1 eq bounds) tp
else BoundedWildcardType(bounds1.asInstanceOf[TypeBounds])
- case RefinedType(parents, decls) =>
+ case rtp @ RefinedType(parents, decls) =>
val parents1 = List.mapConserve(parents)(this)
val decls1 = mapOver(decls)
- if ((parents1 eq parents) && (decls1 eq decls)) tp
- else cloneDecls(refinedType(parents1, tp.symbol.owner), tp, decls1)
+ copyRefinedType(rtp, parents1, decls1)
/*
case ClassInfoType(parents, decls, clazz) =>
val parents1 = List.mapConserve(parents)(this);
@@ -1386,18 +1344,14 @@ trait Types requires SymbolTable {
else cloneDecls(ClassInfoType(parents1, new Scope(), clazz), tp, decls1)
*/
case MethodType(paramtypes, result) =>
- variance = -variance
val paramtypes1 = List.mapConserve(paramtypes)(this)
- variance = -variance
val result1 = this(result)
if ((paramtypes1 eq paramtypes) && (result1 eq result)) tp
else if (tp.isInstanceOf[ImplicitMethodType]) ImplicitMethodType(paramtypes1, result1)
else if (tp.isInstanceOf[JavaMethodType]) JavaMethodType(paramtypes1, result1)
else MethodType(paramtypes1, result1)
case PolyType(tparams, result) =>
- variance = -variance
val tparams1 = mapOver(tparams)
- variance = -variance
var result1 = this(result)
if ((tparams1 eq tparams) && (result1 eq result)) tp
else PolyType(tparams1, result1.substSym(tparams, tparams1))
@@ -1418,16 +1372,6 @@ trait Types requires SymbolTable {
// throw new Error("mapOver inapplicable for " + tp);
}
- def mapOverArgs(args: List[Type], tparams: List[Symbol]): List[Type] =
- map2Conserve(args, tparams) { (arg, tparam) =>
- val v = variance
- if (tparam.isContravariant) variance = -variance
- else if (!tparam.isCovariant) variance = 0
- val arg1 = this(arg)
- variance = v
- arg1
- }
-
/** Map this function over given scope */
private def mapOver(scope: Scope): Scope = {
val elems = scope.toList
@@ -1438,20 +1382,13 @@ trait Types requires SymbolTable {
/** Map this function over given list of symbols */
private def mapOver(syms: List[Symbol]): List[Symbol] = {
- def newInfo(sym: Symbol) = {
- val v = variance
- if (sym.isAliasType) variance = 0
- val result = this(sym.info)
- variance = v
- result
- }
- val infos1 = syms map newInfo
- if (List.forall2(infos1, syms)((info1, sym) => info1 eq sym.info)) syms
+ val infos = syms map (.info)
+ val infos1 = List.mapConserve(infos)(this)
+ if (infos1 eq infos) syms
else {
val syms1 = syms map (.cloneSymbol)
- List.map2(syms1, infos1) { (sym1, info1) =>
- if (isTypeBounds(info1)) sym1 setFlag DEFERRED
- sym1 setInfo info1.substSym(syms, syms1)
+ List.map2(syms1, infos1) {
+ ((sym1, info1) => sym1.setInfo(info1.substSym(syms, syms1)))
}
}
}
@@ -1468,7 +1405,7 @@ trait Types requires SymbolTable {
if ((pre eq NoType) || (pre eq NoPrefix) || !clazz.isClass) tp
else tp match {
case ThisType(sym) =>
- def toPrefix(pre: Type, clazz: Symbol): Type = {
+ def toPrefix(pre: Type, clazz: Symbol): Type =
if ((pre eq NoType) || (pre eq NoPrefix) || !clazz.isClass) tp
else if ((sym isNonBottomSubClass clazz) &&
(pre.widen.symbol isNonBottomSubClass sym))
@@ -1476,8 +1413,7 @@ trait Types requires SymbolTable {
case SuperType(thistp, _) => thistp
case _ => pre
}
- else toPrefix(pre.baseType(clazz).prefix, clazz.owner)
- }
+ else toPrefix(pre.baseType(clazz).prefix, clazz.owner);
toPrefix(pre, clazz)
case TypeRef(prefix, sym, args) if (sym.isTypeParameter) =>
def toInstance(pre: Type, clazz: Symbol): Type =
@@ -1509,50 +1445,8 @@ trait Types requires SymbolTable {
}
toInstance(pre, clazz)
case _ =>
- propagate(mapOver(tp))
+ mapOver(tp)
}
-
- /** Propagate nested type bounds to top-level, or replace by lower/upper bounds
- */
- def propagate(tp: Type): Type =
- if (needsPropagation(tp))
- tp match {
- case TypeBounds(lo, hi) =>
- TypeBounds(lo.lowerBound, hi.upperBound)
- case _ =>
- if (variance == 1) upperBoundMap mapOver tp
- else if (variance == -1) lowerBoundMap mapOver tp
- else TypeBounds(lowerBoundMap mapOver tp, upperBoundMap mapOver tp)
- }
- else tp
-
- /** Does type `tp' contain embedded TypeBounds that need propagating? */
- def needsPropagation(tp: Type): boolean = tp match {
- case SingleType(pre, sym) =>
- isTypeBounds(pre)
- case SuperType(thistp, supertp) =>
- isTypeBounds(thistp) || isTypeBounds(supertp)
- case TypeRef(pre, sym, args) =>
- isTypeBounds(pre)
- case TypeBounds(lo, hi) =>
- isTypeBounds(lo) || isTypeBounds(hi)
- case RefinedType(parents, decls) =>
- (parents exists isTypeBounds) || (decls.toList exists (sym => isTypeBounds(sym.tpe)))
- case MethodType(formals, restpe) =>
- (formals exists isTypeBounds) || isTypeBounds(restpe)
- case PolyType(tparams, result) =>
- isTypeBounds(result)
- case _ =>
- false
- }
- }
-
- object lowerBoundMap extends TypeMap {
- def apply(tp: Type): Type = if (variance == -1) tp.upperBound else tp.lowerBound
- }
-
- object upperBoundMap extends TypeMap {
- def apply(tp: Type): Type = if (variance == -1) tp.lowerBound else tp.upperBound
}
/** A base class to compute all substitutions */
@@ -1589,8 +1483,8 @@ trait Types requires SymbolTable {
class SubstSymMap(from: List[Symbol], to: List[Symbol])
extends SubstMap(from, to) {
protected def toType(fromtp: Type, sym: Symbol) = fromtp match {
- case TypeRef(pre, _, args) => typeRef(pre, sym, args, variance)
- case SingleType(pre, _) => singleType(pre, sym, variance)
+ case TypeRef(pre, _, args) => typeRef(pre, sym, args)
+ case SingleType(pre, _) => singleType(pre, sym)
}
override def apply(tp: Type): Type = {
def subst(sym: Symbol, from: List[Symbol], to: List[Symbol]): Symbol =
@@ -1599,9 +1493,9 @@ trait Types requires SymbolTable {
else subst(sym, from.tail, to.tail)
tp match {
case TypeRef(pre, sym, args) if !(pre eq NoPrefix) =>
- mapOver(typeRef(pre, subst(sym, from, to), args, variance))
+ mapOver(typeRef(pre, subst(sym, from, to), args))
case SingleType(pre, sym) if !(pre eq NoPrefix) =>
- mapOver(singleType(pre, subst(sym, from, to), variance))
+ mapOver(singleType(pre, subst(sym, from, to)))
case _ =>
super.apply(tp)
}
@@ -1730,7 +1624,7 @@ trait Types requires SymbolTable {
val pre1 = this(pre)
val sym1 = adaptToNewRun(pre1, sym)
if ((pre1 eq pre) && (sym1 eq sym)) tp
- else singleType(pre1, sym1, variance)
+ else singleType(pre1, sym1)
}
case TypeRef(pre, sym, args) =>
if (sym.isPackageClass) tp
@@ -1739,7 +1633,7 @@ trait Types requires SymbolTable {
val args1 = List.mapConserve(args)(this)
val sym1 = adaptToNewRun(pre1, sym)
if ((pre1 eq pre) && (sym1 eq sym) && (args1 eq args)/* && sym.isExternal*/) tp
- else typeRef(pre1, sym1, args1, variance)
+ else typeRef(pre1, sym1, args1)
}
case PolyType(tparams, restp) =>
val restp1 = this(restp)
@@ -1908,13 +1802,14 @@ trait Types requires SymbolTable {
case Pair(TypeRef(pre1, sym1, args1), TypeRef(pre2, sym2, args2)) =>
//System.out.println("isSubType " + tp1 + " " + tp2);//DEBUG
def isSubArgs(tps1: List[Type], tps2: List[Type],
- tparams: List[Symbol]): boolean =
- tps1.isEmpty && tps2.isEmpty ||
+ tparams: List[Symbol]): boolean = (
+ tps1.isEmpty && tps2.isEmpty
+ ||
!tps1.isEmpty && !tps2.isEmpty &&
- (tparams.head.isCovariant || (tps2.head.lowerBound <:< tps1.head.lowerBound)) &&
- (tparams.head.isContravariant || (tps1.head.upperBound <:< tps2.head.upperBound)) &&
+ (tparams.head.isCovariant || (tps2.head <:< tps1.head)) &&
+ (tparams.head.isContravariant || (tps1.head <:< tps2.head)) &&
isSubArgs(tps1.tail, tps2.tail, tparams.tail)
-
+ );
(sym1 == sym2 &&
(phase.erasedTypes || pre1 <:< pre2) &&
isSubArgs(args1, args2, sym1.typeParams)
@@ -1944,8 +1839,6 @@ trait Types requires SymbolTable {
res1 <:< res2.substSym(tparams2, tparams1))
case Pair(TypeBounds(lo1, hi1), TypeBounds(lo2, hi2)) =>
lo2 <:< lo1 && hi1 <:< hi2
- case Pair(_, TypeBounds(lo2, hi2)) =>
- lo2 <:< tp1 && tp1 <:< hi2
case Pair(BoundedWildcardType(bounds), _) =>
bounds.lo <:< tp2
case Pair(_, BoundedWildcardType(bounds)) =>
@@ -2054,24 +1947,6 @@ trait Types requires SymbolTable {
cl1
}
- /** like map2, but returns list `xs' itself - instead of a copy - if function
- * <code>f</code> maps all elements to themselves.
- */
- def map2Conserve[A <: AnyRef, B](xs: List[A], ys: List[B])(f: (A, B) => A): List[A] =
- if (xs.isEmpty) xs
- else {
- val x1 = f(xs.head, ys.head)
- val xs1 = map2Conserve(xs.tail, ys.tail)(f)
- if ((x1 eq xs.head) && (xs1 eq xs.tail)) xs
- else x1 :: xs1
- }
-
- /** Is `tp' a TypeBound type? */
- private def isTypeBounds(tp: Type) = tp match {
- case TypeBounds(_, _) => true
- case _ => false
- }
-
// Lubs and Glbs ---------------------------------------------------------
private val recLimit = 10
@@ -2227,6 +2102,7 @@ trait Types requires SymbolTable {
case ts @ MethodType(pts, _) :: rest =>
MethodType(pts, lub0(matchingRestypes(ts, pts)))
case ts @ TypeBounds(_, _) :: rest =>
+ assert(false)
TypeBounds(glb(ts map (.bounds.lo)), lub(ts map (.bounds.hi)))
case ts =>
val closures: List[Array[Type]] = ts map (.closure)
@@ -2328,18 +2204,22 @@ trait Types requires SymbolTable {
proto.cloneSymbol(glbType.symbol).setInfo(
if (proto.isTerm) glb(symtypes)
else {
+ def isTypeBound(tp: Type) = tp match {
+ case TypeBounds(_, _) => true
+ case _ => false
+ }
def glbBounds(bnds: List[Type]): TypeBounds = {
val lo = lub(bnds map (.bounds.lo))
val hi = glb(bnds map (.bounds.hi))
if (lo <:< hi) TypeBounds(lo, hi)
else throw new MalformedClosure(bnds)
}
- val symbounds = symtypes filter isTypeBounds
+ val symbounds = symtypes filter isTypeBound
var result: Type =
if (symbounds.isEmpty)
TypeBounds(AllClass.tpe, AnyClass.tpe)
else glbBounds(symbounds)
- for (val t <- symtypes; !isTypeBounds(t))
+ for (val t <- symtypes; !isTypeBound(t))
if (result.bounds containsType t) result = t
else throw new MalformedClosure(symtypes);
result
@@ -2412,13 +2292,22 @@ trait Types requires SymbolTable {
((tparam, as) =>
if (tparam.variance == variance) lub(as)
else if (tparam.variance == -variance) glb(as)
- else NoType));
- if (args contains NoType) None
- else Some(typeRef(pre, sym, args, variance))
+ else if (lub(as) <:< glb(as)) lub(as)
+ else NoType))
+ try {
+ if (args contains NoType) None
+ else Some(typeRef(pre, sym, args))
+ } catch {
+ case ex: MalformedType => None
+ }
case SingleType(_, sym) :: rest =>
val pres = tps map (.prefix)
val pre = if (variance == 1) lub(pres) else glb(pres)
- Some(singleType(pre, sym, variance))
+ try {
+ Some(singleType(pre, sym))
+ } catch {
+ case ex: MalformedType => None
+ }
}
/** Make symbol <code>sym</code> a member of scope <code>tp.decls</code>
@@ -2517,10 +2406,21 @@ trait Types requires SymbolTable {
* @param required ...
*/
def explainTypes(found: Type, required: Type): unit =
- if (settings.explaintypes.value) {
- val s = explainSwitch
- explainSwitch = true
- found <:< required
- explainSwitch = s
- }
+ if (settings.explaintypes.value) withTypesExplained(found <:< required)
+
+ def withTypesExplained[A](op: => A): A = {
+ val s = explainSwitch
+ explainSwitch = true
+ val result = op
+ explainSwitch = s
+ result
+ }
+
+ def withoutMalformedChecks[T](op: => T): T = {
+ val s = checkMalformedSwitch
+ checkMalformedSwitch = false
+ val result = op
+ checkMalformedSwitch = s
+ result
+ }
}
diff --git a/src/compiler/scala/tools/nsc/transform/UnCurry.scala b/src/compiler/scala/tools/nsc/transform/UnCurry.scala
index 13b8ea7638..c586253333 100644
--- a/src/compiler/scala/tools/nsc/transform/UnCurry.scala
+++ b/src/compiler/scala/tools/nsc/transform/UnCurry.scala
@@ -273,7 +273,7 @@ abstract class UnCurry extends InfoTransform with TypingTransformers {
if (args.isEmpty)
List(mkArrayValue(args))
else {
- val suffix = args.last match {
+ val suffix: Tree = args.last match {
case Typed(arg, Ident(name)) if name == nme.WILDCARD_STAR.toTypeName =>
arg setType seqType(arg.tpe)
case _ =>
diff --git a/src/compiler/scala/tools/nsc/typechecker/Contexts.scala b/src/compiler/scala/tools/nsc/typechecker/Contexts.scala
index 86d572815a..6d2806c6ce 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Contexts.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Contexts.scala
@@ -330,12 +330,20 @@ trait Contexts requires Analyzer {
savedTypeBounds = Pair(sym, sym.info) :: savedTypeBounds
}
- def restoreTypeBounds: unit = {
+ def restoreTypeBounds(tp: Type): Type = {
+ var current = tp
for (val Pair(sym, info) <- savedTypeBounds) {
if (settings.debug.value) log("resetting " + sym + " to " + info);
+ sym.info match {
+ case TypeBounds(lo, hi) if (hi <:< lo && lo <:< hi) =>
+ Console.println("subst "+sym+" to "+lo)
+ current = current.subst(List(sym), List(lo))
+ case _ =>
+ }
sym.setInfo(info)
}
savedTypeBounds = List()
+ current
}
private var implicitsCache: List[List[ImplicitInfo]] = null
diff --git a/src/compiler/scala/tools/nsc/typechecker/Infer.scala b/src/compiler/scala/tools/nsc/typechecker/Infer.scala
index 6a10220cc0..793cceb256 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Infer.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Infer.scala
@@ -106,7 +106,7 @@ trait Infer requires Analyzer {
*/
private def isWithinBounds(tparams: List[Symbol], targs: List[Type]): boolean = {
val bounds = tparams map (.info.subst(tparams, targs).bounds)
- List.map2(bounds, targs)((bound, targ) => bound containsType targ) forall (x => x)
+ !(List.map2(bounds, targs)((bound, targ) => bound containsType targ) contains false)
}
/** Solve constraint collected in types <code>tvars</code>.
@@ -533,11 +533,14 @@ trait Infer requires Analyzer {
def checkBounds(pos: PositionType, tparams: List[Symbol],
targs: List[Type], prefix: String): unit =
if (!isWithinBounds(tparams, targs)) {
- if (!(targs exists (.isErroneous)) && !(tparams exists (.isErroneous)))
+ if (!(targs exists (.isErroneous)) && !(tparams exists (.isErroneous))) {
+ //Console.println("tparams = "+tparams+", bounds = "+tparams.map(.info)+", targs="+targs)//DEBUG
+ //withTypesExplained(isWithinBounds(tparams, targs))//DEBUG
error(pos,
prefix + "type arguments " + targs.mkString("[", ",", "]") +
" do not conform to " + tparams.head.owner + "'s type parameter bounds " +
(tparams map (.defString)).mkString("[", ",", "]"))
+ }
if (settings.explaintypes.value) {
val bounds = tparams map (.info.subst(tparams, targs).bounds)
List.map2(targs, bounds)((targ, bound) => explainTypes(bound.lo, targ))
@@ -625,12 +628,6 @@ trait Infer requires Analyzer {
}
}
- /** Is given type populated? */
- def isPopulated(tp: Type) = tp match {
- case RefinedType(parents, _) => intersectionIsPopulated(parents)
- case _ => true
- }
-
/** Is intersection of given types populated? That is,
* for all types tp1, tp2 in intersection
* for all common base classes bc of tp1 and tp2
@@ -639,22 +636,31 @@ trait Infer requires Analyzer {
* bt1 and bt2 have the same prefix, and
* any correspondiong non-variant type arguments of bt1 and bt2 are the same
*/
- def intersectionIsPopulated(tps: List[Type]) =
- tps.isEmpty || {
- def isConsistent(tp1: Type, tp2: Type): boolean = Pair(tp1, tp2) match {
- case Pair(TypeRef(pre1, sym1, args1), TypeRef(pre2, sym2, args2)) =>
- assert(sym1 == sym2)
- pre1 =:= pre2 &&
- !(List.map3(args1, args2, sym1.typeParams)
- ((arg1, arg2, tparam) => tparam.variance != 0 || arg1 =:= arg2) contains false)
- }
- tps.head.baseClasses forall { bc =>
- tps.tail forall { tp =>
- tp.closurePos(bc) < 0 ||
- isConsistent(tps.head.baseType(bc), tp.baseType(bc))
- }
- }
+ def isPopulated(tp1: Type, tp2: Type): boolean = {
+ def isConsistent(tp1: Type, tp2: Type): boolean = Pair(tp1, tp2) match {
+ case Pair(TypeRef(pre1, sym1, args1), TypeRef(pre2, sym2, args2)) =>
+ assert(sym1 == sym2)
+ pre1 =:= pre2 &&
+ !(List.map3(args1, args2, sym1.typeParams) {
+ (arg1, arg2, tparam) =>
+ //if (tparam.variance == 0 && !(arg1 =:= arg2)) Console.println("inconsistent: "+arg1+"!="+arg2)//DEBUG
+ tparam.variance != 0 || arg1 =:= arg2
+ } contains false)
}
+ if (tp1.symbol.isClass && tp1.symbol.hasFlag(FINAL)) tp1 <:< tp2
+ else tp1.baseClasses forall (bc =>
+ tp2.closurePos(bc) < 0 || isConsistent(tp1.baseType(bc), tp2.baseType(bc)))
+ }
+
+ /** Type with all top-level occurrences of abstract types replaced by their bounds */
+ def widen(tp: Type): Type = tp match {
+ case TypeRef(pre, sym, _) if sym.isAbstractType =>
+ widen(tp.bounds.hi)
+ case rtp @ RefinedType(parents, decls) =>
+ copyRefinedType(rtp, List.mapConserve(parents)(widen), decls)
+ case _ =>
+ tp
+ }
/** Substitite free type variables <code>undetparams</code> of type constructor
* <code>tree</code> in pattern, given prototype <code>pt</code>.
@@ -689,7 +695,6 @@ trait Infer requires Analyzer {
if (restpe.subst(undetparams, tvars) <:< pt) {
computeArgs
} else if (isFullyDefined(pt)) {
-
if (settings.debug.value) log("infer constr " + tree + ":" + restpe + ", pt = " + pt)
var ptparams = freeTypeParams.collect(pt)
if (settings.debug.value) log("free type params = " + ptparams)
@@ -701,29 +706,109 @@ trait Infer requires Analyzer {
if (settings.debug.value) log("new tree = " + tree + ":" + restpe)
val ptvars = ptparams map freshVar
val pt1 = pt.subst(ptparams, ptvars)
- val isCompatible = if (restpe.symbol.hasFlag(FINAL)) restpe <:< pt1
- else intersectionIsPopulated(List(restpe, pt1))
- if (isCompatible) {
- for (val tvar <- ptvars) {
- val tparam = tvar.origin.symbol
- val Pair(loBounds, hiBounds) =
- if (tvar.constr.inst != NoType && isFullyDefined(tvar.constr.inst))
- Pair(List(tvar.constr.inst), List(tvar.constr.inst))
- else
- Pair(tvar.constr.lobounds, tvar.constr.hibounds)
- if (!loBounds.isEmpty || !hiBounds.isEmpty) {
- context.nextEnclosing(.tree.isInstanceOf[CaseDef]).pushTypeBounds(tparam)
- tparam setInfo TypeBounds(
- lub(tparam.info.bounds.lo :: loBounds),
- glb(tparam.info.bounds.hi :: hiBounds))
- if (settings.debug.value) log("new bounds of " + tparam + " = " + tparam.info)
- }
- }
+ if (isPopulated(restpe, pt1)) {
+ ptvars foreach instantiateTypeVar(false)
} else { if (settings.debug.value) System.out.println("no instance: "); instError }
} else { if (settings.debug.value) System.out.println("not a subtype " + restpe.subst(undetparams, tvars) + " of " + ptWithWildcards); instError }
} else { if (settings.debug.value) System.out.println("not fuly defined: " + pt); instError }
}
+ def instantiateTypeVar(aliasOK: boolean)(tvar: TypeVar) = {
+ val tparam = tvar.origin.symbol
+ if (false &&
+ tvar.constr.inst != NoType &&
+ isFullyDefined(tvar.constr.inst) &&
+ (tparam.info.bounds containsType tvar.constr.inst)) {
+ context.nextEnclosing(.tree.isInstanceOf[CaseDef]).pushTypeBounds(tparam)
+ tparam setInfo tvar.constr.inst
+ tparam resetFlag DEFERRED
+ if (settings.debug.value) log("new alias of " + tparam + " = " + tparam.info)
+ } else {
+ val instType = toOrigin(tvar.constr.inst)
+ val Pair(loBounds, hiBounds) =
+ if (instType != NoType && isFullyDefined(instType))
+ Pair(List(instType), List(instType))
+ else
+ Pair(tvar.constr.lobounds, tvar.constr.hibounds)
+ val lo = lub(tparam.info.bounds.lo :: loBounds map toOrigin)
+ val hi = glb(tparam.info.bounds.hi :: hiBounds map toOrigin)
+ if (!(lo <:< hi)) {
+ if (settings.debug.value) log("inconsistent: "+tparam+" "+lo+" "+hi)
+ } else if (!((lo <:< tparam.info.bounds.lo) && (tparam.info.bounds.hi <:< hi))) {
+ context.nextEnclosing(.tree.isInstanceOf[CaseDef]).pushTypeBounds(tparam)
+ tparam setInfo TypeBounds(lo, hi)
+ if (settings.debug.value) log("new bounds of " + tparam + " = " + tparam.info)
+ } else {
+ if (settings.debug.value) log("redundant: "+tparam+" "+tparam.info+"/"+lo+" "+hi)
+ }
+ }
+ }
+
+ def checkCheckable(pos: PositionType, tp: Type): unit = {
+ def patternWarning(tp: Type, prefix: String) =
+ context.unit.deprecationWarning(pos, prefix+tp+" in type pattern is deprecated because it cannot be checked after erasure")
+ def isLocalBinding(sym: Symbol) =
+ sym.isAbstractType &&
+ (sym.name == nme.WILDCARD.toTypeName || {
+ val e = context.scope.lookupEntry(sym.name)
+ e != null && e.sym == sym && e.owner == context.scope
+ })
+ tp match {
+ case SingleType(pre, _) =>
+ checkCheckable(pos, pre)
+ case TypeRef(pre, sym, args) =>
+ if (sym.isAbstractType) patternWarning(tp, "abstract type ")
+ else for (val arg <- args) {
+ if (sym == ArrayClass) checkCheckable(pos, arg)
+ else arg match {
+ case TypeRef(_, sym, _) if isLocalBinding(sym) =>
+ ;
+ case _ =>
+ patternWarning(arg, "non variable type-argument ")
+ }
+ }
+ checkCheckable(pos, pre)
+ case ThisType(_) =>
+ ;
+ case NoPrefix =>
+ ;
+ case _ =>
+ patternWarning(tp, "type pattern ")
+ }
+ }
+
+ def inferTypedPattern(tpt: Tree, pt: Type): Type = {
+ checkCheckable(tpt.pos, tpt.tpe)
+ if (!(tpt.tpe <:< pt)) {
+ val tpparams = freeTypeParams.collect(tpt.tpe)
+ if (settings.debug.value) log("free type params (1) = " + tpparams)
+ var tvars = tpparams map freshVar
+ var tp = tpt.tpe.subst(tpparams, tvars)
+ if (!(tp <:< pt)) {
+ tvars = tpparams map freshVar
+ tp = tpt.tpe.subst(tpparams, tvars)
+ val ptparams = freeTypeParams.collect(pt)
+ if (settings.debug.value) log("free type params (2) = " + ptparams)
+ val ptvars = ptparams map freshVar
+ val pt1 = pt.subst(ptparams, ptvars)
+ if (!isPopulated(tp, pt1)) {
+ error(tpt.pos, "pattern type is incompatibe with expected type"+foundReqMsg(tpt.tpe, pt))
+ return tpt.tpe
+ }
+ ptvars foreach instantiateTypeVar(false)
+ }
+ tvars foreach instantiateTypeVar(true)
+ }
+ intersectionType(List(tpt.tpe, pt))
+ }
+
+ object toOrigin extends TypeMap {
+ def apply(tp: Type): Type = tp match {
+ case TypeVar(origin, _) => origin
+ case _ => mapOver(tp)
+ }
+ }
+
/** A traverser to collect type parameters referred to in a type
*/
object freeTypeParams extends TypeTraverser {
diff --git a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala
index b2815eeddd..fe4beef15f 100644
--- a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala
@@ -93,7 +93,7 @@ abstract class RefChecks extends InfoTransform {
(if (sym1.owner == clazz) ""
else (sym1.locationString +
(if (sym1.isAliasType) ", which equals "+self.memberInfo(sym1)
- else if (sym1.isAbstractType) " with bounds "+self.memberInfo(sym1).bounds.boundsString
+ else if (sym1.isAbstractType) " with bounds "+self.memberInfo(sym1)
else if (sym1.isTerm) " of type "+self.memberInfo(sym1)
else "")))
}
diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
index 9beb1db673..6cabad4aa6 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
@@ -288,10 +288,12 @@ trait Typers requires Analyzer {
!o.privateWithin.ownerChain.contains(sym.owner))
o = o.owner
if (o == sym.owner) badSymbol = sym
- } else if (sym.owner.isTerm) {
- val e = scope.lookupEntry(sym.name)
- if (e != null && e.sym == sym && e.owner == scope && !e.sym.isTypeParameterOrSkolem)
- badSymbol = e.sym
+ } else if (sym.owner.isTerm && !sym.isTypeParameterOrSkolem) {
+ var e = scope.lookupEntry(sym.name)
+ while (e != null && e.owner == scope && badSymbol == NoSymbol) {
+ if (e.sym == sym) badSymbol = e.sym
+ e = scope.lookupNextEntry(e)
+ }
}
}
if (badSymbol == NoSymbol)
@@ -464,7 +466,7 @@ trait Typers requires Analyzer {
if (clazz.hasFlag(CASE)) { // (5.1)
val tree1 = TypeTree(clazz.primaryConstructor.tpe.asSeenFrom(tree.tpe.prefix, clazz.owner)) setOriginal tree
try {
- inferConstructorInstance(tree1, clazz.typeParams, pt)
+ inferConstructorInstance(tree1, clazz.typeParams, widen(pt))
} catch {
case npe : NullPointerException =>
logError("CONTEXT: " + context.unit.source.dbg(tree.pos), npe)
@@ -520,9 +522,9 @@ trait Typers requires Analyzer {
typed(atPos(tree.pos)(Select(qual, nme.apply)), mode, pt)
} else if (!context.undetparams.isEmpty && (mode & POLYmode) == 0) { // (9)
instantiate(tree, mode, pt)
- } else if (tree.tpe <:< pt) {
+ } else if ((mode & PATTERNmode) != 0) {
tree
- } else if ((mode & PATTERNmode) != 0 && treeInfo.isSequencePattern(tree)) {
+ } else if (tree.tpe <:< pt) {
tree
} else {
val tree1 = constfold(tree, pt) // (10) (11)
@@ -998,15 +1000,17 @@ trait Typers requires Analyzer {
else typed(cdef.guard, BooleanClass.tpe)
var body1: Tree = typed(cdef.body, pt)
if (!context.savedTypeBounds.isEmpty) {
- context.restoreTypeBounds
- // the following is a hack to make the pattern matcher work
- body1 =
- typed {
- atPos(body1.pos) {
- TypeApply(Select(body1, Any_asInstanceOf), List(TypeTree(pt)))
+ body1.tpe = context.restoreTypeBounds(body1.tpe)
+ if (isFullyDefined(pt))
+ // the following is a hack to make the pattern matcher work !!! (still needed?)
+ body1 =
+ typed {
+ atPos(body1.pos) {
+ TypeApply(Select(body1, Any_asInstanceOf), List(TypeTree(pt)))
+ }
}
- }
}
+ body1 = checkNoEscaping.locals(context.scope, pt, body1)
copy.CaseDef(cdef, pat1, guard1, body1) setType body1.tpe
}
@@ -1611,8 +1615,22 @@ trait Typers requires Analyzer {
case Bind(name, body) =>
var vble = tree.symbol
- if (vble == NoSymbol) vble = context.owner.newValue(tree.pos, name)
- if (vble.name != nme.WILDCARD) {
+ if (name.isTypeName) {
+ assert(body == EmptyTree)
+ if (vble == NoSymbol)
+ vble =
+ if (isFullyDefined(pt))
+ context.owner.newAliasType(tree.pos, name) setInfo pt
+ else
+ context.owner.newAbstractType(tree.pos, name) setInfo
+ TypeBounds(AllClass.tpe, AnyClass.tpe)
+ if (vble.name == nme.WILDCARD.toTypeName) context.scope.enter(vble)
+ else namer.enterInScope(vble)
+ tree setType vble.tpe
+ } else {
+ if (vble == NoSymbol)
+ vble = context.owner.newValue(tree.pos, name)
+ if (vble.name.toTermName != nme.WILDCARD) {
/*
if (namesSomeIdent(vble.name))
context.unit.warning(tree.pos,
@@ -1620,13 +1638,14 @@ trait Typers requires Analyzer {
"use backquotes `"+vble.name+"` if you mean to match against that value;\n" +
"or rename the variable or use an explicit bind "+vble.name+"@_ to avoid this warning.")
*/
- namer.enterInScope(vble)
+ namer.enterInScope(vble)
+ }
+ val body1 = typed(body, mode, pt)
+ vble.setInfo(
+ if (treeInfo.isSequenceValued(body)) seqType(body1.tpe)
+ else body1.tpe)
+ copy.Bind(tree, name, body1) setSymbol vble setType body1.tpe // buraq, was: pt
}
- val body1 = typed(body, mode, pt)
- vble.setInfo(
- if (treeInfo.isSequenceValued(body)) seqType(body1.tpe)
- else body1.tpe)
- copy.Bind(tree, name, body1) setSymbol vble setType body1.tpe // buraq, was: pt
case ArrayValue(elemtpt, elems) =>
val elemtpt1 = typedType(elemtpt)
@@ -1742,10 +1761,13 @@ trait Typers requires Analyzer {
case _ =>
setError(tree)
}
+
case Typed(expr, tpt) =>
val tpt1 = typedType(tpt)
val expr1 = typed(expr, mode & stickyModes, tpt1.tpe)
- copy.Typed(tree, expr1, tpt1) setType tpt1.tpe
+ val owntype = if ((mode & PATTERNmode) != 0) inferTypedPattern(tpt1, widen(pt)) else tpt1.tpe
+ //Console.println(typed pattern: "+tree+":"+", tp = "+tpt1.tpe+", pt = "+pt+" ==> "+owntype)//DEBUG
+ copy.Typed(tree, expr1, tpt1) setType owntype
case TypeApply(fun, args) =>
val args1 = List.mapConserve(args)(typedType)
@@ -1837,7 +1859,8 @@ trait Typers requires Analyzer {
case Ident(name) =>
idcnt = idcnt + 1
- if (name == nme.WILDCARD && (mode & (PATTERNmode | FUNmode)) == PATTERNmode)
+ if ((name == nme.WILDCARD && (mode & (PATTERNmode | FUNmode)) == PATTERNmode) ||
+ (name == nme.WILDCARD.toTypeName && (mode & TYPEmode) != 0))
tree setType pt
else
typedIdent(name)