diff options
author | Martin Odersky <odersky@gmail.com> | 2006-02-06 18:18:06 +0000 |
---|---|---|
committer | Martin Odersky <odersky@gmail.com> | 2006-02-06 18:18:06 +0000 |
commit | 9668bd2204b7e5b1410bf066f869611618277825 (patch) | |
tree | a3e0a7c1de1883ca8311684714a0433dbf2353e1 | |
parent | b8f52d46645947c523567bc2ecf63168e6ec0cbc (diff) | |
download | scala-9668bd2204b7e5b1410bf066f869611618277825.tar.gz scala-9668bd2204b7e5b1410bf066f869611618277825.tar.bz2 scala-9668bd2204b7e5b1410bf066f869611618277825.zip |
-rw-r--r-- | src/compiler/scala/tools/nsc/Global.scala | 5 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/symtab/Definitions.scala | 3 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/symtab/Types.scala | 41 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/transform/CheckDefined.scala | 83 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/typechecker/Infer.scala | 7 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/typechecker/Typers.scala | 6 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/util/HashSet.scala | 2 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/util/TreeSet.scala | 2 | ||||
-rw-r--r-- | src/library/scala/NonNull.scala | 13 | ||||
-rw-r--r-- | src/library/scala/UndefinedException.scala | 12 | ||||
-rw-r--r-- | src/library/scala/collection/mutable/DoubleLinkedList.scala | 2 | ||||
-rw-r--r-- | src/library/scala/collection/mutable/SingleLinkedList.scala | 4 | ||||
-rw-r--r-- | src/library/scala/concurrent/MailBox.scala | 2 | ||||
-rw-r--r-- | src/library/scala/runtime/ScalaRunTime.scala | 3 |
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(); |