summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMartin Odersky <odersky@gmail.com>2006-02-06 18:18:06 +0000
committerMartin Odersky <odersky@gmail.com>2006-02-06 18:18:06 +0000
commit9668bd2204b7e5b1410bf066f869611618277825 (patch)
treea3e0a7c1de1883ca8311684714a0433dbf2353e1 /src
parentb8f52d46645947c523567bc2ecf63168e6ec0cbc (diff)
downloadscala-9668bd2204b7e5b1410bf066f869611618277825.tar.gz
scala-9668bd2204b7e5b1410bf066f869611618277825.tar.bz2
scala-9668bd2204b7e5b1410bf066f869611618277825.zip
Diffstat (limited to 'src')
-rw-r--r--src/compiler/scala/tools/nsc/Global.scala5
-rw-r--r--src/compiler/scala/tools/nsc/symtab/Definitions.scala3
-rw-r--r--src/compiler/scala/tools/nsc/symtab/Types.scala41
-rw-r--r--src/compiler/scala/tools/nsc/transform/CheckDefined.scala83
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Infer.scala7
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Typers.scala6
-rw-r--r--src/compiler/scala/tools/nsc/util/HashSet.scala2
-rw-r--r--src/compiler/scala/tools/nsc/util/TreeSet.scala2
-rw-r--r--src/library/scala/NonNull.scala13
-rw-r--r--src/library/scala/UndefinedException.scala12
-rw-r--r--src/library/scala/collection/mutable/DoubleLinkedList.scala2
-rw-r--r--src/library/scala/collection/mutable/SingleLinkedList.scala4
-rw-r--r--src/library/scala/concurrent/MailBox.scala2
-rw-r--r--src/library/scala/runtime/ScalaRunTime.scala3
14 files changed, 168 insertions, 17 deletions
diff --git a/src/compiler/scala/tools/nsc/Global.scala b/src/compiler/scala/tools/nsc/Global.scala
index 01a0e070f3..27f3cabd7c 100644
--- a/src/compiler/scala/tools/nsc/Global.scala
+++ b/src/compiler/scala/tools/nsc/Global.scala
@@ -221,6 +221,10 @@ class Global(val settings: Settings, val reporter: Reporter) extends SymbolTable
val global: Global.this.type = Global.this;
}
+ object checkDefined extends CheckDefined {
+ val global: Global.this.type = Global.this;
+ }
+
object explicitOuter extends ExplicitOuter {
val global: Global.this.type = Global.this;
}
@@ -279,6 +283,7 @@ class Global(val settings: Settings, val reporter: Reporter) extends SymbolTable
uncurry,
tailCalls,
transMatcher,
+ checkDefined,
explicitOuter,
erasure,
lambdaLift,
diff --git a/src/compiler/scala/tools/nsc/symtab/Definitions.scala b/src/compiler/scala/tools/nsc/symtab/Definitions.scala
index 7afb631940..83286799bb 100644
--- a/src/compiler/scala/tools/nsc/symtab/Definitions.scala
+++ b/src/compiler/scala/tools/nsc/symtab/Definitions.scala
@@ -71,6 +71,7 @@ mixin class Definitions requires SymbolTable {
var ArrayClass: Symbol = _;
var TypeClass: Symbol = _;
var SerializableClass: Symbol = _;
+ var NonNullClass: Symbol = _;
var PredefModule: Symbol = _;
var ConsoleModule: Symbol = _;
var MatchErrorClass: Symbol = _;
@@ -79,6 +80,7 @@ mixin class Definitions requires SymbolTable {
def MatchError_report = getMember(MatchErrorModule, "report");
var ScalaRunTimeModule: Symbol = _;
def SeqFactory = getMember(ScalaRunTimeModule, "Seq");
+ def checkDefinedMethod = getMember(ScalaRunTimeModule, "checkDefined");
var RepeatedParamClass: Symbol = _;
var ByNameParamClass: Symbol = _;
//var TraitClass: Symbol = _;
@@ -344,6 +346,7 @@ mixin class Definitions requires SymbolTable {
ArrayClass = getClass("scala.Array");
//TypeClass = getClass("scala.Type");
SerializableClass = getClass("java.io.Serializable");
+ NonNullClass = getClass("scala.NonNull");
PredefModule = getModule("scala.Predef");
ConsoleModule = getModule("scala.Console");
MatchErrorClass = getClass("scala.MatchError");
diff --git a/src/compiler/scala/tools/nsc/symtab/Types.scala b/src/compiler/scala/tools/nsc/symtab/Types.scala
index b5df4faec9..19059f12e0 100644
--- a/src/compiler/scala/tools/nsc/symtab/Types.scala
+++ b/src/compiler/scala/tools/nsc/symtab/Types.scala
@@ -49,6 +49,8 @@ mixin class Types requires SymbolTable {
val emptyTypeArray = new Array[Type](0);
+ final val X = true;
+
/** The base class for all types */
abstract class Type {
@@ -125,6 +127,9 @@ mixin class Types requires SymbolTable {
/** Does this type denote a stable reference (i.e. singleton type)? */
def isStable: boolean = false;
+ /** Does this type denote a reference type which can be null? */
+ def isNullable: boolean = false;
+
/** For a classtype or refined type, its defined or declared members;
* inherited by subtypes and typerefs.
* The empty scope for all other types */
@@ -461,17 +466,20 @@ mixin class Types requires SymbolTable {
override def baseType(clazz: Symbol): Type = this;
override def toString(): String = "<error>";
override def narrow: Type = this;
+ override def isNullable: boolean = true;
}
/** An object representing an unknown type */
case object WildcardType extends Type {
override def toString(): String = "?"
+ override def isNullable: boolean = true;
}
/** An object representing a non-existing type */
case object NoType extends Type {
override def isTrivial: boolean = true;
override def toString(): String = "<notype>"
+ override def isNullable: boolean = true;
}
/** An object representing a non-existing prefix */
@@ -480,6 +488,7 @@ mixin class Types requires SymbolTable {
override def isStable: boolean = true;
override def prefixString = "";
override def toString(): String = "<noprefix>";
+ override def isNullable: boolean = true;
}
/** A class for this-types of the form <sym>.this.type
@@ -542,6 +551,7 @@ mixin class Types requires SymbolTable {
def supertype: Type = hi;
override def bounds: TypeBounds = this;
def containsType(that: Type) = that <:< this || lo <:< that && that <:< hi;
+ override def isNullable: boolean = AllRefClass.tpe <:< lo;
override def toString() = ">: " + lo + " <: " + hi;
}
@@ -682,6 +692,9 @@ mixin class Types requires SymbolTable {
override def narrow: Type = symbol.thisType;
+ override def isNullable: boolean =
+ parents forall (p => p.isNullable && !p.symbol.isAbstractType);
+
override def toString(): String = (
parents.mkString("", " with ", "") +
(if (settings.debug.value || parents.isEmpty || decls.elems != null)
@@ -699,9 +712,16 @@ mixin class Types requires SymbolTable {
/** A class representing a class info
*/
- case class ClassInfoType(override val parents: List[Type],
- override val decls: Scope,
- override val symbol: Symbol) extends CompoundType;
+ case class ClassInfoType(
+ override val parents: List[Type],
+ override val decls: Scope,
+ override val symbol: Symbol) extends CompoundType {
+
+ override def isNullable: boolean =
+ symbol == AnyClass ||
+ symbol != AllClass && (symbol isSubClass ObjectClass) && !(symbol isSubClass NonNullClass);
+
+ }
class PackageClassInfoType(decls: Scope, clazz: Symbol) extends ClassInfoType(List(), decls, clazz);
@@ -713,6 +733,7 @@ mixin class Types requires SymbolTable {
override def singleDeref: Type = value.tpe;
override def deconst: Type = value.tpe;
override def toString(): String = value.tpe.toString() + "(" + value.stringValue + ")";
+ override def isNullable: boolean = value.value == null
}
/** A class for named types of the form <prefix>.<sym.name>[args]
@@ -799,6 +820,8 @@ mixin class Types requires SymbolTable {
override def baseClasses: List[Symbol] = sym.info.baseClasses;
+ override def isNullable: boolean = sym.info.isNullable
+
override def toString(): String = {
if (!settings.debug.value) {
if (sym == RepeatedParamClass && !args.isEmpty)
@@ -860,6 +883,8 @@ mixin class Types requires SymbolTable {
override def baseType(clazz: Symbol): Type = resultType.baseType(clazz);
override def narrow: Type = resultType.narrow;
+ override def isNullable: boolean = resultType.isNullable;
+
override def toString(): String =
(if (typeParams.isEmpty) "=> "
else (typeParams map (.defString)).mkString("[", ",", "]")) + resultType;
@@ -1529,7 +1554,9 @@ mixin class Types requires SymbolTable {
||
sym1 == AllClass
||
- sym1 == AllRefClass && sym2 != AllClass && tp2 <:< AnyRefClass.tpe)
+ sym1 == AllRefClass &&
+ (if (X) tp2.isNullable
+ else sym2 != AllClass && tp2 <:< AnyRefClass.tpe))
case Pair(MethodType(pts1, res1), MethodType(pts2, res2)) =>
(pts1.length == pts2.length &&
matchingParams(pts1, pts2, tp2.isInstanceOf[JavaMethodType]) &&
@@ -1564,7 +1591,9 @@ mixin class Types requires SymbolTable {
case Pair(TypeRef(pre1, sym1, args1), _) =>
(sym1 == AllClass && tp2 <:< AnyClass.tpe
||
- sym1 == AllRefClass && tp2.symbol != AllClass && tp2 <:< AnyRefClass.tpe)
+ sym1 == AllRefClass && (
+ if (X) tp2.isNullable
+ else tp2.symbol != AllClass && tp2 <:< AnyRefClass.tpe))
case _ =>
false
}
@@ -1904,7 +1933,7 @@ mixin class Types requires SymbolTable {
}
} catch {
case _: MalformedClosure =>
- if (ts forall (t => t <:< AnyRefClass.tpe)) AllRefClass.tpe
+ if (ts forall (t => if (X) t.isNullable else t <:< AnyRefClass.tpe)) AllRefClass.tpe
else AllClass.tpe
}
}
diff --git a/src/compiler/scala/tools/nsc/transform/CheckDefined.scala b/src/compiler/scala/tools/nsc/transform/CheckDefined.scala
new file mode 100644
index 0000000000..5f4af59553
--- /dev/null
+++ b/src/compiler/scala/tools/nsc/transform/CheckDefined.scala
@@ -0,0 +1,83 @@
+/* NSC -- new scala compiler
+ * Copyright 2005 LAMP/EPFL
+ * @author
+ */
+// $Id: ExplicitOuter.scala 5642 2006-01-26 13:00:58Z odersky $
+package scala.tools.nsc.transform;
+
+import symtab._;
+import Flags._;
+
+abstract class CheckDefined extends Transform {
+ import global._;
+ import definitions._;
+ import posAssigner.atPos;
+
+ /** the following two members override abstract members in Transform */
+ val phaseName: String = "checkdefined";
+
+ protected def newTransformer(unit: CompilationUnit): Transformer =
+ new CheckDefinedTransformer(unit);
+
+ class CheckDefinedTransformer(unit: CompilationUnit) extends Transformer {
+
+ var qualNode: Tree = EmptyTree;
+
+ private def isAlwaysInitialized(tp: Type): boolean = tp match {
+ case ConstantType(_) => true
+ case ThisType(_) => true
+ case SuperType(_, _) => true
+ case SingleType(_, sym) => sym.isModule || isAlwaysInitialized(tp.singleDeref)
+ case TypeRef(_, sym, _) => sym.isModuleClass
+ case _ => false
+ }
+
+ def checkDefined(tree: Tree): Tree = {
+/*
+ System.out.println("check def? " + tree + " " +
+ (tree ne qualNode) + " " +
+ (tree.symbol hasFlag ACCESSOR) + " " +
+ !(tree.symbol hasFlag PARAMACCESSOR) + " " +
+ (tree.tpe <:< AnyClass.tpe) + " " +
+ (tree.tpe.symbol != AllClass) + " " +
+ !tree.tpe.isNullable + " " +
+ !(tree.tpe <:< AnyValClass.tpe) + " " +
+ !isAlwaysInitialized(tree.tpe));
+*/
+ if ((tree ne qualNode) &&
+ (tree.symbol hasFlag ACCESSOR) &&
+ !(tree.symbol hasFlag PARAMACCESSOR) &&
+ (tree.tpe <:< AnyClass.tpe) &&
+ !(tree.tpe <:< AnyValClass.tpe) &&
+ (tree.tpe.symbol != AllClass) &&
+ !tree.tpe.isNullable &&
+ !isAlwaysInitialized(tree.tpe)) {
+ if (settings.debug.value) log("check def " + tree + ":" + tree.tpe + " in " + unit.source.file);
+ atPos(tree.pos) {
+ Apply(
+ TypeApply(
+ gen.mkRef(checkDefinedMethod),
+ List(TypeTree(tree.tpe))
+ ) setType MethodType(List(tree.tpe), tree.tpe),
+ List(tree)
+ ) setType tree.tpe
+ }
+ } else tree;
+ }
+
+ override def transform(tree: Tree): Tree = {
+ tree match {
+ case Select(qual, name) =>
+ val savedQualNode = qualNode;
+ qualNode = qual;
+ val tree1 = super.transform(tree);
+ qualNode = savedQualNode;
+ checkDefined(tree1)
+ case Apply(fn, List()) =>
+ checkDefined(super.transform(tree))
+ case _ =>
+ super.transform(tree)
+ }
+ }
+ }
+}
diff --git a/src/compiler/scala/tools/nsc/typechecker/Infer.scala b/src/compiler/scala/tools/nsc/typechecker/Infer.scala
index 31b7c4a5db..0d8aeec74a 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Infer.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Infer.scala
@@ -208,7 +208,7 @@ mixin class Infer requires Analyzer {
if (!found.isError && !req.isError) {
error(pos,
"type mismatch" + foundReqMsg(found, req) +
- (if (!(found.resultType eq found) && isCompatible(found.resultType, req))
+ (if (!(found.resultType eq found) && isWeaklyCompatible(found.resultType, req))
"\n possible cause: missing arguments for method or constructor"
else ""));
if (settings.explaintypes.value)
@@ -258,6 +258,9 @@ mixin class Infer requires Analyzer {
(tp1 <:< pt) || isCoercible(tp, pt)
}
+ def isWeaklyCompatible(tp: Type, pt: Type): boolean =
+ pt.symbol == UnitClass || isCompatible(tp, pt);
+
def isCoercible(tp: Type, pt: Type): boolean = false;
def isCompatible(tps: List[Type], pts: List[Type]): boolean =
@@ -378,7 +381,7 @@ mixin class Infer requires Analyzer {
if (undetparams.isEmpty) {
(formals.length == argtpes.length &&
isCompatible(argtpes, formals) &&
- isCompatible(restpe, pt))
+ isWeaklyCompatible(restpe, pt))
} else {
try {
val uninstantiated = new ListBuffer[Symbol];
diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
index 4472ab9def..3fb8af5111 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
@@ -377,8 +377,7 @@ mixin class Typers requires Analyzer {
} else {
clazz.initialize
if (clazz.hasFlag(CASE)) { // (5.1)
- val tree1 = TypeTree(clazz.primaryConstructor.tpe.asSeenFrom(tree.tpe.prefix, clazz.owner)) setOriginal(tree)
-
+ val tree1 = TypeTree(clazz.primaryConstructor.tpe.asSeenFrom(tree.tpe.prefix, clazz.owner)) setPos tree.pos
// tree.tpe.prefix.memberType(clazz.primaryConstructor); //!!!
inferConstructorInstance(tree1, clazz.unsafeTypeParams, pt)
@@ -1286,7 +1285,8 @@ mixin class Typers requires Analyzer {
.setPos(tpt1.pos)
.setType(appliedType(tpt1.tpe, context.undetparams map (.tpe)))
}
- if (tpt1.tpe.symbol.isMixin) error(tree.pos, "mixin classes cannot be instantiated")
+ if (tpt1.tpe.symbol hasFlag ABSTRACT)
+ error(tree.pos, ""+tpt1.tpe.symbol+" is abstract; cannot be instantiated")
copy.New(tree, tpt1).setType(tpt1.tpe)
case Typed(expr, tpt @ Ident(name)) if (name == nme.WILDCARD_STAR.toTypeName) =>
diff --git a/src/compiler/scala/tools/nsc/util/HashSet.scala b/src/compiler/scala/tools/nsc/util/HashSet.scala
index d74d7e9582..9164ee527e 100644
--- a/src/compiler/scala/tools/nsc/util/HashSet.scala
+++ b/src/compiler/scala/tools/nsc/util/HashSet.scala
@@ -5,7 +5,7 @@
// $Id$
package scala.tools.nsc.util;
-class HashSet[T <: AnyRef](initialCapacity: int) extends Set[T] {
+class HashSet[T >: AllRef <: AnyRef](initialCapacity: int) extends Set[T] {
private var capacity = initialCapacity;
private var used = 0;
diff --git a/src/compiler/scala/tools/nsc/util/TreeSet.scala b/src/compiler/scala/tools/nsc/util/TreeSet.scala
index 552f06b3f4..574a0cc532 100644
--- a/src/compiler/scala/tools/nsc/util/TreeSet.scala
+++ b/src/compiler/scala/tools/nsc/util/TreeSet.scala
@@ -7,7 +7,7 @@ package scala.tools.nsc.util;
/** Sets implemented as binary trees.
*/
-class TreeSet[T <: AnyRef](less: (T, T) => boolean) extends Set[T] {
+class TreeSet[T >: AllRef <: AnyRef](less: (T, T) => boolean) extends Set[T] {
private class Tree(val elem: T) {
var l: Tree = null;
diff --git a/src/library/scala/NonNull.scala b/src/library/scala/NonNull.scala
new file mode 100644
index 0000000000..02a037ccf0
--- /dev/null
+++ b/src/library/scala/NonNull.scala
@@ -0,0 +1,13 @@
+/* __ *\
+** ________ ___ / / ___ Scala API **
+** / __/ __// _ | / / / _ | (c) 2002-2005, LAMP/EPFL **
+** __\ \/ /__/ __ |/ /__/ __ | **
+** /____/\___/_/ |_/____/_/ | | **
+** |/ **
+\* */
+
+// $Id: ScalaObject.scala 5390 2005-12-19 13:49:03Z dubochet $
+
+package scala;
+
+trait NonNull;
diff --git a/src/library/scala/UndefinedException.scala b/src/library/scala/UndefinedException.scala
new file mode 100644
index 0000000000..d88cb0a5ca
--- /dev/null
+++ b/src/library/scala/UndefinedException.scala
@@ -0,0 +1,12 @@
+/* __ *\
+** ________ ___ / / ___ Scala API **
+** / __/ __// _ | / / / _ | (c) 2002, LAMP/EPFL **
+** __\ \/ /__/ __ |/ /__/ __ | **
+** /____/\___/_/ |_/____/_/ | | **
+** |/ **
+** **
+** $Id: MatchError.scala 5390 2005-12-19 13:49:03Z dubochet $
+\* */
+package scala;
+
+final class UndefinedException extends RuntimeException;
diff --git a/src/library/scala/collection/mutable/DoubleLinkedList.scala b/src/library/scala/collection/mutable/DoubleLinkedList.scala
index 4b79ba534c..0fefcf6b04 100644
--- a/src/library/scala/collection/mutable/DoubleLinkedList.scala
+++ b/src/library/scala/collection/mutable/DoubleLinkedList.scala
@@ -19,7 +19,7 @@ package scala.collection.mutable;
* @version 1.0, 08/07/2003
*/
[serializable]
-abstract class DoubleLinkedList[A, This <: DoubleLinkedList[A, This]] requires This
+abstract class DoubleLinkedList[A, This >: AllRef <: DoubleLinkedList[A, This]] requires This
extends SingleLinkedList[A, This] {
var prev: This = _;
diff --git a/src/library/scala/collection/mutable/SingleLinkedList.scala b/src/library/scala/collection/mutable/SingleLinkedList.scala
index 9ec97f39ff..52c2fdcd35 100644
--- a/src/library/scala/collection/mutable/SingleLinkedList.scala
+++ b/src/library/scala/collection/mutable/SingleLinkedList.scala
@@ -19,13 +19,13 @@ package scala.collection.mutable;
* @version 1.0, 08/07/2003
*/
[serializable]
-abstract class SingleLinkedList[A, This <: SingleLinkedList[A, This]]
+abstract class SingleLinkedList[A, This >: AllRef <: SingleLinkedList[A, This]]
requires This
extends AnyRef with Seq[A] {
var elem: A = _;
- var next: This = _;
+ var next: This = null;
def length: Int = 1 + (if (next == null) 0 else next.length);
diff --git a/src/library/scala/concurrent/MailBox.scala b/src/library/scala/concurrent/MailBox.scala
index 427d424b28..4463071f2e 100644
--- a/src/library/scala/concurrent/MailBox.scala
+++ b/src/library/scala/concurrent/MailBox.scala
@@ -137,7 +137,7 @@ trait ListQueueCreator {
/** Efficient queue module creator based on linked lists. */
trait LinkedListQueueCreator {
import scala.collection.mutable.LinkedList;
- def queueCreate[a <: AnyRef]: QueueModule[a] = new QueueModule[a] {
+ def queueCreate[a >: AllRef <: AnyRef]: QueueModule[a] = new QueueModule[a] {
type t = Pair[LinkedList[a], LinkedList[a]]; // fst = the list, snd = last elem
def make: t = {
val l = new LinkedList[a](null, null);
diff --git a/src/library/scala/runtime/ScalaRunTime.scala b/src/library/scala/runtime/ScalaRunTime.scala
index 827e4cc223..77d46fc745 100644
--- a/src/library/scala/runtime/ScalaRunTime.scala
+++ b/src/library/scala/runtime/ScalaRunTime.scala
@@ -88,6 +88,9 @@ object ScalaRunTime {
false
}
+ def checkDefined[T >: AllRef](x: T): T =
+ if (x == null) throw new UndefinedException else x
+
def Seq[a](xs: a*): Seq[a] = null; // interpreted specially by new backend.
def booleanValue(x: BoxedBoolean): Boolean = if (x eq null) false else x.booleanValue();