Skip to content

Commit 56c7306

Browse files
committed
Check good usage of opaque flag at desugar
This is a template for checking the other flags as well (e.g. the outstanding problem how to check the `enum` flag could be solved like this.
1 parent ab456d6 commit 56c7306

File tree

2 files changed

+43
-12
lines changed

2 files changed

+43
-12
lines changed

compiler/src/dotty/tools/dotc/ast/Desugar.scala

Lines changed: 43 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1035,19 +1035,51 @@ object desugar {
10351035
Bind(name, Ident(nme.WILDCARD)).withSpan(tree.span)
10361036
}
10371037

1038-
def defTree(tree: Tree)(implicit ctx: Context): Tree = tree match {
1039-
case tree: ValDef => valDef(tree)
1040-
case tree: TypeDef =>
1041-
if (tree.isClassDef) classDef(tree)
1042-
else if (tree.mods.is(Opaque, butNot = Synthetic)) opaqueAlias(tree)
1043-
else tree
1044-
case tree: DefDef =>
1045-
if (tree.name.isConstructorName) tree // was already handled by enclosing classDef
1046-
else defDef(tree)
1047-
case tree: ModuleDef => moduleDef(tree)
1048-
case tree: PatDef => patDef(tree)
1038+
/** The type of tests that check whether a MemberDef is OK for some flag.
1039+
* The test succeeds if the partial function is defined and returns true.
1040+
*/
1041+
type MemberDefTest = PartialFunction[MemberDef, Boolean]
1042+
1043+
val legalOpaque: MemberDefTest = {
1044+
case TypeDef(_, rhs) =>
1045+
def rhsOK(tree: Tree): Boolean = tree match {
1046+
case _: TypeBoundsTree | _: Template => false
1047+
case LambdaTypeTree(_, body) => rhsOK(body)
1048+
case _ => true
1049+
}
1050+
rhsOK(rhs)
1051+
}
1052+
1053+
/** Check that modifiers are legal for the definition `tree`.
1054+
* Right now, we only check for `opaque`. TODO: Move other modifier checks here.
1055+
*/
1056+
def checkModifiers(tree: Tree)(implicit ctx: Context): Tree = tree match {
1057+
case tree: MemberDef =>
1058+
var tested: MemberDef = tree
1059+
def fail(msg: String) = ctx.error(msg, tree.sourcePos)
1060+
def checkApplicable(flag: FlagSet, test: MemberDefTest): Unit =
1061+
if (tested.mods.is(flag) && !(test.isDefinedAt(tree) && test(tree))) {
1062+
fail(i"modifier `$flag` is not allowed for this definition")
1063+
tested = tested.withMods(tested.mods.withoutFlags(flag))
1064+
}
1065+
checkApplicable(Opaque, legalOpaque)
1066+
tested
1067+
case _ =>
1068+
tree
10491069
}
10501070

1071+
def defTree(tree: Tree)(implicit ctx: Context): Tree =
1072+
checkModifiers(tree) match {
1073+
case tree: ValDef => valDef(tree)
1074+
case tree: TypeDef =>
1075+
if (tree.isClassDef) classDef(tree) else tree
1076+
case tree: DefDef =>
1077+
if (tree.name.isConstructorName) tree // was already handled by enclosing classDef
1078+
else defDef(tree)
1079+
case tree: ModuleDef => moduleDef(tree)
1080+
case tree: PatDef => patDef(tree)
1081+
}
1082+
10511083
/** { stats; <empty > }
10521084
* ==>
10531085
* { stats; () }

compiler/src/dotty/tools/dotc/typer/Checking.scala

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -441,7 +441,6 @@ object Checking {
441441
checkNoConflict(Lazy, ParamAccessor, s"parameter may not be `lazy`")
442442
if (sym.is(Inline)) checkApplicable(Inline, sym.isTerm && !sym.is(Mutable | Module))
443443
if (sym.is(Lazy)) checkApplicable(Lazy, !sym.is(Method | Mutable))
444-
if (sym.is(Opaque, butNot = (Synthetic | Module))) checkApplicable(Opaque, sym.isAliasType)
445444
if (sym.isType && !sym.is(Deferred))
446445
for (cls <- sym.allOverriddenSymbols.filter(_.isClass)) {
447446
fail(CannotHaveSameNameAs(sym, cls, CannotHaveSameNameAs.CannotBeOverridden))

0 commit comments

Comments
 (0)