summaryrefslogtreecommitdiff
path: root/src/compiler
diff options
context:
space:
mode:
authorMartin Odersky <odersky@gmail.com>2007-05-11 00:14:07 +0000
committerMartin Odersky <odersky@gmail.com>2007-05-11 00:14:07 +0000
commitb40e3b35cecdf7d827ce360dedf86d37767bbda8 (patch)
tree05f96e07808c2473ce32be1a30e4bff161574531 /src/compiler
parent48c9a76728c38b178d061bb6a282826a82cf77d3 (diff)
downloadscala-b40e3b35cecdf7d827ce360dedf86d37767bbda8.tar.gz
scala-b40e3b35cecdf7d827ce360dedf86d37767bbda8.tar.bz2
scala-b40e3b35cecdf7d827ce360dedf86d37767bbda8.zip
Fixed several bugs, added dependent method types.
Diffstat (limited to 'src/compiler')
-rw-r--r--src/compiler/scala/tools/nsc/ast/TreePrinters.scala2
-rw-r--r--src/compiler/scala/tools/nsc/ast/Trees.scala46
-rw-r--r--src/compiler/scala/tools/nsc/symtab/Types.scala152
-rw-r--r--src/compiler/scala/tools/nsc/symtab/classfile/PickleFormat.scala6
-rw-r--r--src/compiler/scala/tools/nsc/symtab/classfile/Pickler.scala4
-rw-r--r--src/compiler/scala/tools/nsc/symtab/classfile/UnPickler.scala2
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Infer.scala18
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Namers.scala54
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/RefChecks.scala1
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Typers.scala29
10 files changed, 253 insertions, 61 deletions
diff --git a/src/compiler/scala/tools/nsc/ast/TreePrinters.scala b/src/compiler/scala/tools/nsc/ast/TreePrinters.scala
index 1ae4120bb2..f331208752 100644
--- a/src/compiler/scala/tools/nsc/ast/TreePrinters.scala
+++ b/src/compiler/scala/tools/nsc/ast/TreePrinters.scala
@@ -279,7 +279,7 @@ abstract class TreePrinters {
if (!qual.isEmpty) print(symName(tree, qual) + ".")
print("this")
- case Select(qual @ New(tpe), name) =>
+ case Select(qual @ New(tpe), name) if (!settings.debug.value) =>
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 9a163b698b..fc47701fe8 100644
--- a/src/compiler/scala/tools/nsc/ast/Trees.scala
+++ b/src/compiler/scala/tools/nsc/ast/Trees.scala
@@ -76,7 +76,7 @@ trait Trees {
def pos = rawpos
var tpe: Type = _
- //var kindStar = false //@M: kindStar implies !tpe.isHigherKinded --> if true, setType does not accept higher-kinded types
+
def setPos(pos: Position): this.type = { rawpos = pos; this }
def setType(tp: Type): this.type = { /*assert(kindingIrrelevant(tp) || !kindStar || !tp.isHigherKinded, ""+tp+" should not be higher-kinded");*/ tpe = tp; this }
@@ -720,49 +720,93 @@ trait Trees {
/* A standard pattern match
case EmptyTree =>
case PackageDef(name, stats) =>
+ // package name { stats }
case ClassDef(mods, name, tparams, self, impl) =>
+ // mods class name[tparams] requires self impl
case ModuleDef(mods, name, impl) => (eliminated by refcheck)
+ // mods object name impl where impl = extends parents { defs }
case ValDef(mods, name, tpt, rhs) =>
+ // mods val name: tpt = rhs
case DefDef(mods, name, tparams, vparamss, tpt, rhs) =>
+ // mods def name[tparams](vparams): tpt = rhs
case AbsTypeDef(mods, name, tparams, lo, hi) => (eliminated by erasure)
+ // mods type name[tparams] >: lo <: hi
case AliasTypeDef(mods, name, tparams, rhs) => (eliminated by erasure)
+ // mods type name[tparams] = rhs
case LabelDef(name, params, rhs) =>
+ // used for tailcalls and like
case Import(expr, selectors) => (eliminated by typecheck)
+ // import expr.{selectors}
case Annotation(constr, elements) => (eliminated by typecheck)
+ // @constr(elements) where constr = tp(args), elements = { val x1 = c1, ..., val xn = cn }
case DocDef(comment, definition) => (eliminated by typecheck)
+ // /** comment */ definition
case Template(parents, body) =>
+ // extends parents { body }
case Block(stats, expr) =>
+ // { stats; expr }
case CaseDef(pat, guard, body) => (eliminated by transmatch/explicitouter)
+ // case pat if guard => body
case Sequence(trees) => (eliminated by transmatch/explicitouter)
+ // pat1, ..., pat_n
case Alternative(trees) => (eliminated by transmatch/explicitouter)
+ // pat1 | ... | patn
case Star(elem) => (eliminated by transmatch/explicitouter)
+ // pat*
case Bind(name, body) => (eliminated by transmatch/explicitouter)
+ // name @ pat
case UnApply(fun: Tree, args) (introduced by typer, eliminated by transmatch/explicitouter)
+ // used for unapply's
case ArrayValue(elemtpt, trees) => (introduced by uncurry)
+ // used to pass arguments to vararg arguments
case Function(vparams, body) => (eliminated by lambdaLift)
+ // vparams => body where vparams:List[ValDef]
case Assign(lhs, rhs) =>
+ // lhs = rhs
case If(cond, thenp, elsep) =>
+ // if (cond) thenp else elsep
case Match(selector, cases) =>
+ // selector match { cases }
case Return(expr) =>
+ // return expr
case Try(block, catches, finalizer) =>
+ // try block catch { catches } finally finalizer where catches: List[CaseDef]
case Throw(expr) =>
+ // throw expr
case New(tpt) =>
+ // new tpt always in the context: new tpt.<init>[targs](args)
case Typed(expr, tpt) => (eliminated by erasure)
+ // expr: tpt
case TypeApply(fun, args) =>
+ // fun[args]
case Apply(fun, args) =>
+ // fun(args)
case ApplyDynamic(qual, args) (introduced by erasure, eliminated by cleanup)
+ // fun(args)
case Super(qual, mix) =>
+ // qual.super[mix]
case This(qual) =>
+ // qual.this
case Select(qualifier, selector) =>
+ // qualifier.selector
case Ident(name) =>
+ // name
case Literal(value) =>
+ // value
case TypeTree() => (introduced by refcheck)
+ // a type that's not written out, but given in the attribute
case Annotated(annot, arg) => (eliminated by typer)
+ // arg @annot for types, arg: @annot for exprs
case SingletonTypeTree(ref) => (eliminated by uncurry)
+ // ref.type
case SelectFromTypeTree(qualifier, selector) => (eliminated by uncurry)
+ // qualifier # selector, a path-dependent type p.T is expressed as p.type # T
case CompoundTypeTree(templ: Template) => (eliminated by uncurry)
+ // parent1 with ... with parentN { refinement }
case AppliedTypeTree(tpt, args) => (eliminated by uncurry)
+ // tpt[args]
case WildcardTypeTree(lo, hi) => (eliminated by uncurry)
+ // todo: get rid of that!
*/
abstract class TreeCopier {
diff --git a/src/compiler/scala/tools/nsc/symtab/Types.scala b/src/compiler/scala/tools/nsc/symtab/Types.scala
index 156f79617e..861606fa66 100644
--- a/src/compiler/scala/tools/nsc/symtab/Types.scala
+++ b/src/compiler/scala/tools/nsc/symtab/Types.scala
@@ -13,23 +13,43 @@ import Flags._
/* A standard type pattern match:
case ErrorType =>
+ // internal: error
case WildcardType =>
+ // internal: unknown
case NoType =>
case NoPrefix =>
- case ThisType(_) =>
+ case ThisType(sym) =>
+ // sym.this.type
case SingleType(pre, sym) =>
+ // pre.sym.type
case ConstantType(value) =>
+ // int(2)
case TypeRef(pre, sym, args) =>
- case TypeBounds(lo, hi) =>
+ // pre.sym[targs]
case RefinedType(parents, defs) =>
+ // parent1 with ... with parentn { defs }
+ case AnnotatedType(attribs, tp) =>
+ // tp @attribs
+
+ // the following are non-value types; you cannot write them down in Scala source.
+
+ case TypeBounds(lo, hi) =>
+ // >: lo <: hi
case ClassInfoType(parents, defs, clazz) =>
+ // same as RefinedType except as body of class
case MethodType(paramtypes, result) =>
+ // (paramtypes)result
case PolyType(tparams, result) =>
- // the last three types are not used after phase `typer'.
+ // [tparams]result where result is a MethodType or ClassInfoType
+
+ // the last five types are not used after phase `typer'.
+
case OverloadedType(pre, tparams, alts) =>
+ // all alternatives of an overloaded ident
case AntiPolyType(pre: Type, targs) =>
case TypeVar(_, _) =>
- case AnnotatedType(attribs, tp) =>
+ // a type variable
+ case DeBruijnIndex(level, index)
*/
trait Types {
@@ -74,6 +94,11 @@ trait Types {
// the following are all operations in class Type that are overridden in some subclass
// Important to keep this up-to-date when new operations are added!
override def isTrivial = tp.isTrivial
+ override def isHigherKinded: boolean = tp.isHigherKinded
+ override def isNotNull = tp.isNotNull
+ override def isError = tp.isError
+ override def isErroneous = tp.isErroneous
+ override def isStable: boolean = tp.isStable
override def symbol = tp.symbol
override def singleDeref = maybeRewrap(tp.singleDeref)
override def widen = maybeRewrap(tp.widen)
@@ -85,6 +110,7 @@ trait Types {
override def prefix = tp.prefix
override def typeArgs = tp.typeArgs
override def resultType = maybeRewrap(tp.resultType)
+ override def resultType(actuals: List[Type]) = maybeRewrap(tp.resultType(actuals))
override def finalResultType = maybeRewrap(tp.finalResultType)
override def paramSectionCount = tp.paramSectionCount
override def paramTypes = tp.paramTypes
@@ -92,12 +118,7 @@ trait Types {
override def notNull = maybeRewrap(tp.notNull)
override def instantiateTypeParams(formals: List[Symbol], actuals: List[Type]) =
tp.instantiateTypeParams(formals, actuals)
- override def isHigherKinded: boolean = tp.isHigherKinded
override def normalize = maybeRewrap(tp.normalize)
- override def isError = tp.isError
- override def isErroneous = tp.isErroneous
- override def isStable: boolean = tp.isStable
- override def isNotNull = tp.isNotNull
override def decls = tp.decls
override def baseType(clazz: Symbol) = tp.baseType(clazz)
override def closure = tp.closure
@@ -120,6 +141,22 @@ trait Types {
*/
def isTrivial: boolean = false
+ /** Is this type higher-kinded, i.e., is it a type constructor @M */
+ def isHigherKinded: boolean = false
+
+ /** Does this type denote a stable reference (i.e. singleton type)? */
+ def isStable: boolean = false
+
+ /** Is this type guaranteed not to have `null' as a value? */
+ def isNotNull: boolean = false
+
+ /** Does this depend on an enclosing method parameter? */
+ def isDependent: boolean = {
+ IsDependentTraverser.result = false
+ IsDependentTraverser.traverse(this)
+ IsDependentTraverser.result
+ }
+
/** The symbol associated with the type
* Note that the symbol of the normalized type is returned (@see normalize)
*/
@@ -170,6 +207,10 @@ trait Types {
* the type itself for all other types */
def resultType: Type = this
+ def resultType(actuals: List[Type]) = this
+
+ def resultApprox: Type = ApproximateDeBruijnMap(resultType)
+
/** For a curried method or poly type its non-method result type,
* the type itself for all other types */
def finalResultType: Type = this
@@ -188,7 +229,7 @@ trait Types {
/** Mixin a NotNull trait unless type already has one */
def notNull: Type =
- if (isNotNull) this else NotNullType(this)
+ if (isNotNull || phase.erasedTypes) this else NotNullType(this)
/** Replace formal type parameter symbols with actual type arguments.
*
@@ -196,9 +237,6 @@ trait Types {
*/
def instantiateTypeParams(formals: List[Symbol], actuals: List[Type]): Type = this.subst(formals, actuals)
- /** Is this type higher-kinded, i.e., is it a type constructor @M */
- def isHigherKinded: boolean = false
-
/** Reduce to beta eta-long normal form. Expands type aliases and converts higher-kinded TypeRef's to PolyTypes. @M */
def normalize = this // @MAT
@@ -212,12 +250,6 @@ trait Types {
ErroneousTraverser.result
}
- /** Does this type denote a stable reference (i.e. singleton type)? */
- def isStable: boolean = false
-
- /** Is this type guaranteed not to have `null' as a value? */
- def isNotNull: boolean = false
-
/** Does this type denote a reference type which can be null? */
// def isNullable: boolean = false
@@ -694,6 +726,12 @@ trait Types {
override def narrow: Type = this
}
+ case class DeBruijnIndex(level: int, paramId: int) extends Type {
+ override def isTrivial = true
+ override def isStable = true
+ override def toString = "<param "+level+"."+paramId+">"
+ }
+
/** A class for singleton types of the form &lt;prefix&gt;.&lt;sym.name&gt;.type.
* Cannot be created directly; one should always use
* <code>singleType</code> for creation.
@@ -1121,6 +1159,8 @@ trait Types {
override val isTrivial: boolean =
pre.isTrivial && !sym.isTypeParameter && args.forall(.isTrivial)
+ override def isNotNull = sym.isModuleClass
+
// @M: propagate actual type params (args) to `tp', by replacing formal type parameters with actual ones
def transform(tp: Type): Type =
tp.asSeenFrom(pre, sym.owner).instantiateTypeParams(sym.typeParams, argsMaybeDummy)
@@ -1202,6 +1242,7 @@ A type's symbol should never be inspected directly.
override def normalize =
if (sym.isAliasType) {
if (sym.info.typeParams.length == args.length || !sym.info.isComplete) // beta-reduce -- check if the info has been loaded, if not, the arity check is meaningless
+ // Martin to Adriaan: I believe sym.info.isComplete is redundant here
transform(sym.info.resultType).normalize // cycles have been checked in typeRef
else if (isHigherKinded)
PolyType(typeParams, transform(sym.info.resultType).normalize)
@@ -1296,15 +1337,29 @@ A type's symbol should never be inspected directly.
//assert(paramTypes forall (pt => !pt.symbol.isImplClass))//DEBUG
override def paramSectionCount: int = resultType.paramSectionCount + 1
+ override def resultType(actuals: List[Type]) =
+ new InstantiateDeBruijnMap(actuals).apply(resultType)
+
override def finalResultType: Type = resultType.finalResultType
+ protected def paramPrefix = "("
+
+ private def dependentToString(base: int): String = {
+ val params = for ((pt, n) <- paramTypes.zipWithIndex) yield "x$"+n+":"+pt
+ val res = resultType match {
+ case mt: MethodType => mt.dependentToString(base + params.length)
+ case rt => rt.toString
+ }
+ params.mkString(paramPrefix, ",", ")")+res
+ }
+
override def toString(): String =
- paramTypes.mkString("(", ",", ")") + resultType
+ if (resultType.isDependent) dependentToString(0)
+ else paramTypes.mkString(paramPrefix, ",", ")") + resultType
}
class ImplicitMethodType(pts: List[Type], rt: Type) extends MethodType(pts, rt) {
- override def toString(): String =
- paramTypes.mkString("(implicit ", ",", ")") + resultType
+ override protected def paramPrefix = "(implicit "
}
class JavaMethodType(pts: List[Type], rt: Type) extends MethodType(pts, rt)
@@ -1709,6 +1764,7 @@ A type's symbol should never be inspected directly.
case NoPrefix => tp
case ThisType(_) => tp
case ConstantType(_) => tp
+ case DeBruijnIndex(_, _) => tp
case SingleType(pre, sym) =>
if (sym.isPackageClass) tp // short path
else {
@@ -1764,9 +1820,7 @@ A type's symbol should never be inspected directly.
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)
+ else copyMethodType(tp, paramtypes1, result1)
case PolyType(tparams, result) =>
variance = -variance
val tparams1 = mapOver(tparams)
@@ -1829,6 +1883,12 @@ A type's symbol should never be inspected directly.
}
}
}
+
+ protected def copyMethodType(tp: Type, formals: List[Type], restpe: Type): Type = tp match {
+ case _: ImplicitMethodType => ImplicitMethodType(formals, restpe)
+ case _: JavaMethodType => JavaMethodType(formals, restpe)
+ case _ => MethodType(formals, restpe)
+ }
}
abstract class TypeTraverser extends TypeMap {
@@ -1996,6 +2056,26 @@ A type's symbol should never be inspected directly.
def apply(tp: Type): Type = if (tp eq from) to else mapOver(tp)
}
+ class InstantiateDeBruijnMap(actuals: List[Type]) extends TypeMap {
+ def apply(tp: Type): Type = tp match {
+ case DeBruijnIndex(level, pid) =>
+ if (level == 1)
+ if (pid < actuals.length) actuals(pid) else tp
+ else DeBruijnIndex(level - 1, pid)
+ case _ =>
+ mapOver(tp)
+ }
+ }
+
+ object ApproximateDeBruijnMap extends TypeMap {
+ def apply(tp: Type): Type = tp match {
+ case DeBruijnIndex(level, pid) =>
+ WildcardType
+ case _ =>
+ mapOver(tp)
+ }
+ }
+
/** A map to convert every occurrence of a wildcard type to a fresh
* type variable */
object wildcardToTypeVarMap extends TypeMap {
@@ -2048,6 +2128,17 @@ A type's symbol should never be inspected directly.
}
}
+ object IsDependentTraverser extends TypeTraverser {
+ var result: boolean = _
+ def traverse(tp: Type): TypeTraverser = {
+ tp match {
+ case DeBruijnIndex(_, _) => result = true
+ case _ => if (!result) mapOver(tp)
+ }
+ this
+ }
+ }
+
/** A map to compute the most deeply nested owner that contains all the symbols
* of thistype or prefixless typerefs/singletype occurrences in given type.
*/
@@ -2420,10 +2511,6 @@ A type's symbol should never be inspected directly.
atp1 <:< tp2
case (_, AnnotatedType(_,atp2)) =>
tp1 <:< atp2
- case (NotNullType(ntp1), _) =>
- ntp1 <:< tp2
- case (_, NotNullType(ntp2)) =>
- tp1.isNotNull && tp1 <:< ntp2
case (_, _) if (tp1.isHigherKinded || tp2.isHigherKinded) =>
(tp1.symbol == AllClass
||
@@ -2436,7 +2523,8 @@ A type's symbol should never be inspected directly.
sym2 == NotNullClass && tp1.isNotNull) =>
true
case (_, RefinedType(parents2, ref2)) =>
- (parents2 forall tp1.<:<) && (ref2.toList forall tp1.specializes) &&
+ (parents2 forall (tp2 => tp1 <:< tp2 || tp2.symbol == NotNullClass && tp1.isNotNull)) &&
+ (ref2.toList forall tp1.specializes) &&
(!parents2.exists(.symbol.isAbstractType) || tp1.symbol != AllRefClass)
case (RefinedType(parents1, ref1), _) =>
parents1 exists (.<:<(tp2))
@@ -2445,6 +2533,10 @@ A type's symbol should never be inspected directly.
| {SingleType(_, _), _}
| {ConstantType(_), _} =>
once patern matching bug is fixed */
+ case (_, NotNullType(ntp2)) =>
+ tp1.isNotNull && tp1 <:< ntp2
+ case (NotNullType(ntp1), _) =>
+ ntp1 <:< tp2
case (ThisType(_), _) => tp1.singleDeref <:< tp2
case (SingleType(_, _), _) => tp1.singleDeref <:< tp2
case (ConstantType(_), _) =>
diff --git a/src/compiler/scala/tools/nsc/symtab/classfile/PickleFormat.scala b/src/compiler/scala/tools/nsc/symtab/classfile/PickleFormat.scala
index 86077f5852..39e96cbfcf 100644
--- a/src/compiler/scala/tools/nsc/symtab/classfile/PickleFormat.scala
+++ b/src/compiler/scala/tools/nsc/symtab/classfile/PickleFormat.scala
@@ -52,6 +52,7 @@ object PickleFormat {
* | 35 LITERALclass len_Nat type_Ref
* | 40 ATTRIBUTE len_Nat sym_Ref info_Ref {constant_Ref} {nameRef constantRef}
* | 41 CHILDREN len_Nat sym_Ref {sym_Ref}
+ * | 47 DEBRUIJNINDEXtpe len_Nat level_Nat index_Nat
* | 68 PosTYPEsym len_Nat pos_Nat SymbolInfo
* | 69 PosALIASsym len_Nat pos_Nat SymbolInfo
* | 70 PosCLASSsym len_Nat pos_Nat SymbolInfo [thistype_Ref]
@@ -89,6 +90,7 @@ object PickleFormat {
final val METHODtpe = 20
final val POLYtpe = 21
final val IMPLICITMETHODtpe = 22
+
final val LITERAL = 23 // base line for literals
final val LITERALunit = 24
final val LITERALboolean = 25
@@ -106,10 +108,7 @@ object PickleFormat {
final val CHILDREN = 41
final val ANNOTATEDtpe = 42
-
-
final val ATTRIBTREE = 43 // an annotation with trees
-
final val REFLTREE = 44 // prefix saying that a prefix tree is coming
final val IDENTtree = 1
final val SELECTtree = 2
@@ -155,6 +154,7 @@ object PickleFormat {
final val ROOTSYMBOLrsym = 8
final val LABELSYMBOLrsym = 9
+ final val DEBRUIJNINDEXtpe = 47
final val firstSymTag = NONEsym
final val lastSymTag = VALsym
diff --git a/src/compiler/scala/tools/nsc/symtab/classfile/Pickler.scala b/src/compiler/scala/tools/nsc/symtab/classfile/Pickler.scala
index f3f123cf1a..8371a8a857 100644
--- a/src/compiler/scala/tools/nsc/symtab/classfile/Pickler.scala
+++ b/src/compiler/scala/tools/nsc/symtab/classfile/Pickler.scala
@@ -138,7 +138,7 @@ abstract class Pickler extends SubComponent {
*/
private def putType(tp: Type): unit = if (putEntry(tp)) {
tp match {
- case NoType | NoPrefix =>
+ case NoType | NoPrefix | DeBruijnIndex(_, _) =>
;
case ThisType(sym) =>
putSymbol(sym)
@@ -388,6 +388,8 @@ abstract class Pickler extends SubComponent {
else METHODtpe
case PolyType(tparams, restpe) =>
writeRef(restpe); writeRefs(tparams); POLYtpe
+ case DeBruijnIndex(l, i) =>
+ writeNat(l); writeNat(i); DEBRUIJNINDEXtpe
case c @ Constant(_) =>
if (c.tag == BooleanTag) writeLong(if (c.booleanValue) 1 else 0)
else if (ByteTag <= c.tag && c.tag <= LongTag) writeLong(c.longValue)
diff --git a/src/compiler/scala/tools/nsc/symtab/classfile/UnPickler.scala b/src/compiler/scala/tools/nsc/symtab/classfile/UnPickler.scala
index 75074162b9..5e3c4a5ce0 100644
--- a/src/compiler/scala/tools/nsc/symtab/classfile/UnPickler.scala
+++ b/src/compiler/scala/tools/nsc/symtab/classfile/UnPickler.scala
@@ -264,6 +264,8 @@ abstract class UnPickler {
// This way, people can distribute classfiles
// including annotated types without them much
// affecting those who disable -Xplugtypes
+ case DEBRUIJNINDEXtpe =>
+ DeBruijnIndex(readNat(), readNat())
case _ =>
errorBadSignature("bad type tag: " + tag)
}
diff --git a/src/compiler/scala/tools/nsc/typechecker/Infer.scala b/src/compiler/scala/tools/nsc/typechecker/Infer.scala
index 39f8893fbd..1f2305446b 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Infer.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Infer.scala
@@ -211,7 +211,7 @@ trait Infer {
* @return ...
*/
def normalize(tp: Type): Type = skipImplicit(tp) match {
- case MethodType(formals, restpe) =>
+ case MethodType(formals, restpe) if (!restpe.isDependent) =>
if (util.Statistics.enabled) normM = normM + 1
functionType(formals, normalize(restpe))
case PolyType(List(), restpe) =>
@@ -269,7 +269,7 @@ trait Infer {
def typeErrorMsg(found: Type, req: Type) =
"type mismatch" + foundReqMsg(found, req) +
- (if (!(found.resultType eq found) && isWeaklyCompatible(found.resultType, req))
+ (if ((found.resultApprox ne found) && isWeaklyCompatible(found.resultApprox, req))
"\n possible cause: missing arguments for method or constructor"
else "")
@@ -385,9 +385,9 @@ trait Infer {
}
def isPlausiblyCompatible(tp: Type, pt: Type): boolean = tp match {
- case PolyType(_, restp) =>
- isPlausiblyCompatible(restp, pt)
- case MethodType(formals, restp) =>
+ case PolyType(_, restpe) =>
+ isPlausiblyCompatible(restpe, pt)
+ case MethodType(formals, _) =>
pt.normalize match {
case TypeRef(pre, sym, args) =>
!sym.isClass || {
@@ -395,7 +395,7 @@ trait Infer {
l == formals.length &&
sym == FunctionClass(l) &&
List.forall2(args, formals) (isPlausiblySubType) &&
- isPlausiblySubType(restp, args.last)
+ isPlausiblySubType(tp.resultApprox, args.last)
}
case _ =>
true
@@ -572,9 +572,10 @@ trait Infer {
def isApplicable(undetparams: List[Symbol], ftpe: Type,
argtpes0: List[Type], pt: Type): boolean =
ftpe match {
- case MethodType(formals0, restpe) =>
+ case MethodType(formals0, _) =>
val formals = formalTypes(formals0, argtpes0.length)
val argtpes = actualTypes(argtpes0, formals.length)
+ val restpe = ftpe.resultType(argtpes)
if (undetparams.isEmpty) {
(formals.length == argtpes.length &&
isCompatible(argtpes, formals) &&
@@ -809,10 +810,11 @@ trait Infer {
*/
def inferMethodInstance(fn: Tree, undetparams: List[Symbol],
args: List[Tree], pt: Type): List[Symbol] = fn.tpe match {
- case MethodType(formals0, restpe) =>
+ case MethodType(formals0, _) =>
try {
val formals = formalTypes(formals0, args.length)
val argtpes = actualTypes(args map (.tpe.deconst), formals.length)
+ val restpe = fn.tpe.resultType(argtpes)
val uninstantiated = new ListBuffer[Symbol]
val targs = methTypeArgs(undetparams, formals, restpe, argtpes, pt, uninstantiated)
checkBounds(fn.pos, NoPrefix, NoSymbol, undetparams, targs, "inferred ")
diff --git a/src/compiler/scala/tools/nsc/typechecker/Namers.scala b/src/compiler/scala/tools/nsc/typechecker/Namers.scala
index 7b0eb3bc2c..9fa3f66cf9 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Namers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Namers.scala
@@ -471,22 +471,62 @@ trait Namers requires Analyzer {
val tparamSyms = typer.reenterTypeParams(tparams)
var vparamSymss = enterValueParams(meth, vparamss)
- if (tpt.isEmpty && meth.name == nme.CONSTRUCTOR) tpt.tpe = context.enclClass.owner.tpe.notNull
+ if (tpt.isEmpty && meth.name == nme.CONSTRUCTOR) tpt.tpe = context.enclClass.owner.tpe
if (onlyPresentation)
methodArgumentNames(meth) = vparamss.map(.map(.symbol));
+ def convertToDeBruijn(vparams: List[Symbol], level: int): TypeMap = new TypeMap {
+ def apply(tp: Type) = {
+ tp match {
+ case SingleType(_, sym) =>
+ if (settings.Xexperimental.value && sym.owner == meth && (vparams contains sym)) {
+ if (sym hasFlag IMPLICIT) {
+ context.error(sym.pos, "illegal type dependence on implicit parameter")
+ ErrorType
+ } else DeBruijnIndex(level, vparams indexOf sym)
+ } else tp
+ case MethodType(formals, restpe) =>
+ val formals1 = List.mapConserve(formals)(this)
+ val restpe1 = convertToDeBruijn(vparams, level + 1)(restpe)
+ if ((formals1 eq formals) && (restpe1 eq restpe)) tp
+ else copyMethodType(tp, formals1, restpe1)
+ case _ =>
+ mapOver(tp)
+ }
+ }
+ }
+
+ val checkDependencies: TypeTraverser = new TypeTraverser {
+ def traverse(tp: Type) = {
+ tp match {
+ case SingleType(_, sym) =>
+ if (settings.Xexperimental.value && sym.owner == meth &&
+ (vparamSymss exists (_ contains sym)))
+ context.error(
+ sym.pos,
+ "illegal dependent method type: parameter appears in the type "+
+ "of another parameter in the same section or an earlier one")
+ case _ =>
+ mapOver(tp)
+ }
+ this
+ }
+ }
+
def makeMethodType(vparams: List[Symbol], restpe: Type) = {
- val formals = vparams map (.tpe)
- if (!vparams.isEmpty && vparams.head.hasFlag(IMPLICIT)) ImplicitMethodType(formals, restpe)
- else MethodType(formals, restpe)
+ val formals = vparams map (_.tpe)
+ val restpe1 = convertToDeBruijn(vparams, 1)(restpe)
+ if (!vparams.isEmpty && vparams.head.hasFlag(IMPLICIT))
+ ImplicitMethodType(formals, restpe1)
+ else MethodType(formals, restpe1)
}
- def thisMethodType(restype: Type) =
+ def thisMethodType(restpe: Type) =
parameterizedType(
tparamSyms,
- if (vparamSymss.isEmpty) PolyType(List(), restype)
- else (vparamSymss :\ restype)(makeMethodType))
+ if (vparamSymss.isEmpty) PolyType(List(), restpe)
+ else checkDependencies((vparamSymss :\ restpe) (makeMethodType)))
var resultPt = if (tpt.isEmpty) WildcardType else typer.typedType(tpt).tpe
val site = meth.owner.thisType
diff --git a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala
index a629f0c645..295f040aae 100644
--- a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala
@@ -392,6 +392,7 @@ abstract class RefChecks extends InfoTransform {
case NoPrefix => ;
case ThisType(_) => ;
case ConstantType(_) => ;
+ case DeBruijnIndex(_, _) => ;
case SingleType(pre, sym) =>
validateVariance(pre, variance)
case TypeRef(pre, sym, args) =>
diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
index 9868d83b83..4c8076d706 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
@@ -293,6 +293,8 @@ trait Typers requires Analyzer {
error(pos, "methods with `=>'-parameter can be converted to function values only if they take no other parameters")
if (formals exists (.symbol.==(RepeatedParamClass)))
error(pos, "methods with `*'-parameters cannot be converted to function values");
+ if (restpe.isDependent)
+ error(pos, "method with dependent type "+tpe+" cannot be converted to function value");
checkParamsConvertible(pos, restpe)
case _ =>
}
@@ -1152,13 +1154,13 @@ trait Typers requires Analyzer {
val tparams1 = List.mapConserve(ddef.tparams)(typedAbsTypeDef)
val vparamss1 = List.mapConserve(ddef.vparamss)(vparams1 =>
List.mapConserve(vparams1)(typedValDef))
- for (val vparams <- vparamss1; val vparam <- vparams) {
- checkNoEscaping.locals(context.scope, WildcardType, vparam.tpt); ()
+ var tpt1 = checkNoEscaping.privates(meth, typedType(ddef.tpt))
+ if (!settings.Xexperimental.value) {
+ for (val vparams <- vparamss1; val vparam <- vparams) {
+ checkNoEscaping.locals(context.scope, WildcardType, vparam.tpt); ()
+ }
+ checkNoEscaping.locals(context.scope, WildcardType, tpt1)
}
- var tpt1 =
- checkNoEscaping.locals(context.scope, WildcardType,
- checkNoEscaping.privates(meth,
- typedType(ddef.tpt)))
checkNonCyclic(ddef, tpt1)
ddef.tpt.setType(tpt1.tpe)
var rhs1 =
@@ -1492,7 +1494,7 @@ trait Typers requires Analyzer {
context.undetparams = undetparams
inferMethodAlternative(fun, context.undetparams, args1 map (.tpe.deconst), pt)
doTypedApply(tree, adapt(fun, funMode(mode), WildcardType), args1, mode, pt)
- case MethodType(formals0, restpe) =>
+ case mt @ MethodType(formals0, _) =>
val formals = formalTypes(formals0, args.length)
var args1 = actualArgs(tree.pos, args, formals.length)
if (args1.length != args.length) {
@@ -1507,6 +1509,7 @@ trait Typers requires Analyzer {
context.undetparams = List()
if (tparams.isEmpty) {
val args2 = typedArgs(args1, argMode(fun, mode), formals0, formals)
+ val restpe = mt.resultType(args2 map (_.tpe))
def ifPatternSkipFormals(tp: Type) = tp match {
case MethodType(_, rtp) if ((mode & PATTERNmode) != 0) => rtp
case _ => tp
@@ -1553,7 +1556,7 @@ trait Typers requires Analyzer {
constfold(copy.Apply(tree, fun, args2).setType(ifPatternSkipFormals(restpe)))
} else {
assert((mode & PATTERNmode) == 0); // this case cannot arise for patterns
- val lenientTargs = protoTypeArgs(tparams, formals, restpe, pt)
+ val lenientTargs = protoTypeArgs(tparams, formals, mt.resultApprox, pt)
val strictTargs = List.map2(lenientTargs, tparams)((targ, tparam) =>
if (targ == WildcardType) tparam.tpe else targ)
def typedArgToPoly(arg: Tree, formal: Type): Tree = {
@@ -1597,7 +1600,7 @@ trait Typers requires Analyzer {
if (!isApplicableSafe(List(), unappType, List(arg.tpe), WildcardType)) {
//Console.println("UNAPP: need to typetest, arg.tpe = "+arg.tpe+", unappType = "+unappType)
def freshArgType(tp: Type): (Type, List[Symbol]) = tp match {
- case MethodType(formals, restpe) =>
+ case MethodType(formals, _) =>
(formals(0), List())
case PolyType(tparams, restype) =>
val tparams1 = cloneSymbols(tparams)
@@ -2021,6 +2024,11 @@ trait Typers requires Analyzer {
} else {
doTypedApply(tree, fun2, args, mode, pt)
}
+ /*
+ if (fun2.hasSymbol && fun2.symbol.isConstructor && (mode & EXPRmode) != 0) {
+ res.tpe = res.tpe.notNull
+ }
+ */
if (fun2.symbol == Array_apply) typed { atPos(tree.pos) { gen.mkCheckInit(res) } }
else res
@@ -2185,8 +2193,9 @@ trait Typers requires Analyzer {
val result = stabilize(checkAccessible(tree1, sym, qual.tpe, qual), qual.tpe, mode, pt)
if (sym.isCaseFactory && !phase.erasedTypes) checkStable(qual)
if (!global.phase.erasedTypes && settings.checknull.value &&
+ !sym.isConstructor &&
!(qual.tpe <:< NotNullClass.tpe) && !qual.tpe.isNotNull)
- unit.warning(tree.pos, "potential null pointer dereference")
+ unit.warning(tree.pos, "potential null pointer dereference: "+tree)
result
}
}