aboutsummaryrefslogtreecommitdiff
path: root/src/dotty/tools/dotc
diff options
context:
space:
mode:
authorMartin Odersky <odersky@gmail.com>2015-10-21 17:49:27 +0200
committerMartin Odersky <odersky@gmail.com>2015-10-22 12:21:26 +0200
commitf1b3859911ee04a90a0b169c5eefa2c64ce5d265 (patch)
tree0d8d90bc89d62a83c7bd1395ecac1e43f922bd09 /src/dotty/tools/dotc
parent54f5899b0888983495f5ff70f561d9634350f3f2 (diff)
downloaddotty-f1b3859911ee04a90a0b169c5eefa2c64ce5d265.tar.gz
dotty-f1b3859911ee04a90a0b169c5eefa2c64ce5d265.tar.bz2
dotty-f1b3859911ee04a90a0b169c5eefa2c64ce5d265.zip
Add well-formedness checking for created symbols
Enforces various restrictions of definitions.
Diffstat (limited to 'src/dotty/tools/dotc')
-rw-r--r--src/dotty/tools/dotc/typer/Checking.scala43
-rw-r--r--src/dotty/tools/dotc/typer/Namer.scala20
2 files changed, 61 insertions, 2 deletions
diff --git a/src/dotty/tools/dotc/typer/Checking.scala b/src/dotty/tools/dotc/typer/Checking.scala
index 8f4a8b72b..1c0274c84 100644
--- a/src/dotty/tools/dotc/typer/Checking.scala
+++ b/src/dotty/tools/dotc/typer/Checking.scala
@@ -230,6 +230,49 @@ object Checking {
}
checkTree((), refinement)
}
+
+ /** Check that symbol's definition is well-formed. */
+ def checkWellFormed(sym: Symbol)(implicit ctx: Context): Unit = {
+ //println(i"check wf $sym with flags ${sym.flags}")
+ def fail(msg: String) = ctx.error(msg, sym.pos)
+ def varNote =
+ if (sym.is(Mutable)) "\n(Note that variables need to be initialized to be defined)"
+ else ""
+
+ def checkWithDeferred(flag: FlagSet) =
+ if (sym.is(flag))
+ fail(i"abstract member may not have `$flag' modifier")
+ def checkNoConflict(flag1: FlagSet, flag2: FlagSet) =
+ if (sym.is(allOf(flag1, flag2)))
+ fail(i"illegal combination of modifiers: $flag1 and $flag2 for: $sym")
+
+ if (sym.is(ImplicitCommon)) {
+ if (sym.owner.is(Package))
+ fail(i"`implicit' modifier cannot be used for top-level definitions")
+ if (sym.isType)
+ fail(i"`implicit' modifier cannot be used for types or traits")
+ }
+ if (!sym.isClass && sym.is(Abstract))
+ fail(i"`abstract' modifier can be used only for classes; it should be omitted for abstract members")
+ if (sym.is(AbsOverride) && !sym.owner.is(Trait))
+ fail(i"`abstract override' modifier only allowed for members of traits")
+ if (sym.is(Trait) && sym.is(Final))
+ fail(i"$sym may not be `final'")
+ if (sym.hasAnnotation(defn.NativeAnnot))
+ if (sym.is(Deferred)) sym.resetFlag(Deferred)
+ else fail(i"`@native' members may not have implementation")
+ if (sym.is(Deferred, butNot = Param) && !sym.isSelfSym) {
+ if (!sym.owner.isClass || sym.owner.is(Module) || sym.owner.isAnonymousClass)
+ fail(i"only classes can have declared but undefined members$varNote")
+ checkWithDeferred(Private)
+ checkWithDeferred(Final)
+ }
+ if (sym.isValueClass && sym.is(Trait) && !sym.isRefinementClass)
+ fail(i"$sym cannot extend AnyVal")
+ checkNoConflict(Final, Sealed)
+ checkNoConflict(Private, Protected)
+ checkNoConflict(Abstract, Override)
+ }
}
trait Checking {
diff --git a/src/dotty/tools/dotc/typer/Namer.scala b/src/dotty/tools/dotc/typer/Namer.scala
index d97bbff91..52989c1a5 100644
--- a/src/dotty/tools/dotc/typer/Namer.scala
+++ b/src/dotty/tools/dotc/typer/Namer.scala
@@ -234,6 +234,18 @@ class Namer { typer: Typer =>
sym
}
+ def checkFlags(flags: FlagSet) =
+ if (flags.isEmpty) flags
+ else {
+ val (ok, adapted, kind) = tree match {
+ case tree: TypeDef => (flags.isTypeFlags, flags.toTypeFlags, "type")
+ case _ => (flags.isTermFlags, flags.toTermFlags, "value")
+ }
+ if (!ok)
+ ctx.error(i"modifier(s) `$flags' incompatible with $kind definition", tree.pos)
+ adapted
+ }
+
/** Add moduleClass/sourceModule to completer if it is for a module val or class */
def adjustIfModule(completer: LazyType, tree: MemberDef) =
if (tree.mods is Module) ctx.adjustModuleCompleter(completer, tree.name.encode)
@@ -261,14 +273,16 @@ class Namer { typer: Typer =>
tree match {
case tree: TypeDef if tree.isClassDef =>
val name = checkNoConflict(tree.name.encode).asTypeName
+ val flags = checkFlags(tree.mods.flags &~ Implicit)
val cls = record(ctx.newClassSymbol(
- ctx.owner, name, tree.mods.flags | inSuperCall,
+ ctx.owner, name, flags | inSuperCall,
cls => adjustIfModule(new ClassCompleter(cls, tree)(ctx), tree),
privateWithinClass(tree.mods), tree.pos, ctx.source.file))
cls.completer.asInstanceOf[ClassCompleter].init()
cls
case tree: MemberDef =>
val name = checkNoConflict(tree.name.encode)
+ val flags = checkFlags(tree.mods.flags)
val isDeferred = lacksDefinition(tree)
val deferred = if (isDeferred) Deferred else EmptyFlags
val method = if (tree.isInstanceOf[DefDef]) Method else EmptyFlags
@@ -291,7 +305,7 @@ class Namer { typer: Typer =>
val cctx = if (tree.name == nme.CONSTRUCTOR && !(tree.mods is JavaDefined)) ctx.outer else ctx
record(ctx.newSymbol(
- ctx.owner, name, tree.mods.flags | deferred | method | higherKinded | inSuperCall1,
+ ctx.owner, name, flags | deferred | method | higherKinded | inSuperCall1,
adjustIfModule(new Completer(tree)(cctx), tree),
privateWithinClass(tree.mods), tree.pos))
case tree: Import =>
@@ -517,6 +531,7 @@ class Namer { typer: Typer =>
def completeInCreationContext(denot: SymDenotation): Unit = {
denot.info = typeSig(denot.symbol)
addAnnotations(denot)
+ Checking.checkWellFormed(denot.symbol)
}
}
@@ -585,6 +600,7 @@ class Namer { typer: Typer =>
index(rest)(inClassContext(selfInfo))
denot.info = ClassInfo(cls.owner.thisType, cls, parentRefs, decls, selfInfo)
addAnnotations(denot)
+ Checking.checkWellFormed(cls)
if (isDerivedValueClass(cls)) cls.setFlag(Final)
cls.setApplicableFlags(
(NoInitsInterface /: impl.body)((fs, stat) => fs & defKind(stat)))