diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/dotty/tools/dotc/ast/tpd.scala | 5 | ||||
-rw-r--r-- | src/dotty/tools/dotc/core/Types.scala | 2 | ||||
-rw-r--r-- | src/dotty/tools/dotc/parsing/Parsers.scala | 12 | ||||
-rw-r--r-- | src/dotty/tools/dotc/repl/InterpreterLoop.scala | 3 | ||||
-rw-r--r-- | src/dotty/tools/dotc/repl/ManifestInfo.scala | 20 | ||||
-rw-r--r-- | src/dotty/tools/dotc/reporting/diagnostic/Message.scala | 5 | ||||
-rw-r--r-- | src/dotty/tools/dotc/reporting/diagnostic/messages.scala | 112 | ||||
-rw-r--r-- | src/dotty/tools/dotc/transform/ExplicitOuter.scala | 20 | ||||
-rw-r--r-- | src/dotty/tools/dotc/typer/Namer.scala | 11 | ||||
-rw-r--r-- | src/dotty/tools/dotc/typer/RefChecks.scala | 11 |
10 files changed, 168 insertions, 33 deletions
diff --git a/src/dotty/tools/dotc/ast/tpd.scala b/src/dotty/tools/dotc/ast/tpd.scala index db2ce5649..fc96735b0 100644 --- a/src/dotty/tools/dotc/ast/tpd.scala +++ b/src/dotty/tools/dotc/ast/tpd.scala @@ -306,8 +306,8 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo { case _ => false } - typeIsElidable || - tp.symbol.is(JavaStatic) || + typeIsElidable || + tp.symbol.is(JavaStatic) || tp.symbol.hasAnnotation(defn.ScalaStaticAnnot) } @@ -343,6 +343,7 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo { def singleton(tp: Type)(implicit ctx: Context): Tree = tp match { case tp: TermRef => ref(tp) case tp: ThisType => This(tp.cls) + case tp: SkolemType => singleton(tp.narrow) case SuperType(qual, _) => singleton(qual) case ConstantType(value) => Literal(value) } diff --git a/src/dotty/tools/dotc/core/Types.scala b/src/dotty/tools/dotc/core/Types.scala index ce308412b..ae248295c 100644 --- a/src/dotty/tools/dotc/core/Types.scala +++ b/src/dotty/tools/dotc/core/Types.scala @@ -73,6 +73,8 @@ object Types { * +- NoPrefix * +- ErrorType * +- WildcardType + * + * Note: please keep in sync with copy in `docs/docs/internals/type-system.md`. */ abstract class Type extends DotClass with Hashable with printing.Showable { diff --git a/src/dotty/tools/dotc/parsing/Parsers.scala b/src/dotty/tools/dotc/parsing/Parsers.scala index f442c13b3..aade359f8 100644 --- a/src/dotty/tools/dotc/parsing/Parsers.scala +++ b/src/dotty/tools/dotc/parsing/Parsers.scala @@ -151,7 +151,7 @@ object Parsers { /* ------------- ERROR HANDLING ------------------------------------------- */ /** The offset of the last time when a statement on a new line was definitely - * encountered in the current scope or an outer scope\ + * encountered in the current scope or an outer scope. */ private var lastStatOffset = -1 @@ -505,7 +505,7 @@ object Parsers { if (t1 ne t) t1 else dotSelectors(selector(t), finish) } - /** Dotelectors ::= { `.' ident() + /** DotSelectors ::= { `.' ident() * * Accept `.' separated identifiers acting as a selectors on given tree `t`. * @param finish An alternative parse in case the token following a `.' is not an identifier. @@ -521,7 +521,7 @@ object Parsers { * | [Ident `.'] this * * @param thisOK If true, [Ident `.'] this is acceptable as the path. - * If false, another selection is required aftre the `this`. + * If false, another selection is required after the `this`. * @param finish An alternative parse in case the token following a `.' is not an identifier. * If the alternative does not apply, its tree argument is returned unchanged. */ @@ -1076,7 +1076,7 @@ object Parsers { val uscoreStart = in.skipToken() if (isIdent(nme.raw.STAR)) { in.nextToken() - if (in.token != RPAREN) syntaxError("`_*' can be used only for last argument", uscoreStart) + if (in.token != RPAREN) syntaxError(SeqWildcardPatternPos(), uscoreStart) Typed(t, atPos(uscoreStart) { Ident(tpnme.WILDCARD_STAR) }) } else { syntaxErrorOrIncomplete(IncorrectRepeatedParameterSyntax()) @@ -1424,7 +1424,7 @@ object Parsers { // `x: _*' is parsed in `ascription' if (isIdent(nme.raw.STAR)) { in.nextToken() - if (in.token != RPAREN) syntaxError("`_*' can be used only for last argument", wildIndent.pos) + if (in.token != RPAREN) syntaxError(SeqWildcardPatternPos(), wildIndent.pos) atPos(wildIndent.pos) { Ident(tpnme.WILDCARD_STAR) } } else wildIndent case LPAREN => @@ -1436,7 +1436,7 @@ object Parsers { case _ => if (isLiteral) literal() else { - syntaxErrorOrIncomplete("illegal start of simple pattern") + syntaxErrorOrIncomplete(IllegalStartOfSimplePattern()) errorTermTree } } diff --git a/src/dotty/tools/dotc/repl/InterpreterLoop.scala b/src/dotty/tools/dotc/repl/InterpreterLoop.scala index 8b1000f2e..b3ac41c55 100644 --- a/src/dotty/tools/dotc/repl/InterpreterLoop.scala +++ b/src/dotty/tools/dotc/repl/InterpreterLoop.scala @@ -66,7 +66,8 @@ class InterpreterLoop(compiler: Compiler, config: REPL.Config)(implicit ctx: Con output.flush() } - val version = ".next (pre-alpha)" + val gitHash = ManifestInfo.attributes.getOrElse("Git-Hash", "unknown") + val version = s".next (pre-alpha, git-hash: $gitHash)" /** The main read-eval-print loop for the interpreter. It calls * `command()` for each line of input. diff --git a/src/dotty/tools/dotc/repl/ManifestInfo.scala b/src/dotty/tools/dotc/repl/ManifestInfo.scala new file mode 100644 index 000000000..206dccd67 --- /dev/null +++ b/src/dotty/tools/dotc/repl/ManifestInfo.scala @@ -0,0 +1,20 @@ +package dotty.tools.dotc.repl + +import java.net.JarURLConnection +import scala.collection.JavaConversions._ + +object ManifestInfo { + + val attributes: Map[String, String] = { + for { + resourceUrl <- Option(getClass.getResource(getClass.getSimpleName + ".class")) + urlConnection = resourceUrl.openConnection() if urlConnection.isInstanceOf[JarURLConnection] + manifest <- Option(urlConnection.asInstanceOf[JarURLConnection].getManifest) + } yield { + manifest.getMainAttributes.foldLeft(Map[String, String]())( + (map, attribute) => map + (attribute._1.toString -> attribute._2.toString) + ) + } + }.getOrElse(Map()) + +} diff --git a/src/dotty/tools/dotc/reporting/diagnostic/Message.scala b/src/dotty/tools/dotc/reporting/diagnostic/Message.scala index 8b1f65673..8b607c18c 100644 --- a/src/dotty/tools/dotc/reporting/diagnostic/Message.scala +++ b/src/dotty/tools/dotc/reporting/diagnostic/Message.scala @@ -18,7 +18,8 @@ object Message { /** A `Message` contains all semantic information necessary to easily * comprehend what caused the message to be logged. Each message can be turned * into a `MessageContainer` which contains the log level and can later be - * consumed by a subclass of `Reporter`. + * consumed by a subclass of `Reporter`. However, the error position is only + * part of `MessageContainer`, not `Message`. * * @param errorId a unique number identifying the message, this will later be * used to reference documentation online @@ -31,7 +32,7 @@ abstract class Message(val errorId: Int) { self => * > expected: String * > found: Int * - * This message wil be placed underneath the position given by the enclosing + * This message will be placed underneath the position given by the enclosing * `MessageContainer` */ def msg: String diff --git a/src/dotty/tools/dotc/reporting/diagnostic/messages.scala b/src/dotty/tools/dotc/reporting/diagnostic/messages.scala index 649f2a8f8..5e6a402ef 100644 --- a/src/dotty/tools/dotc/reporting/diagnostic/messages.scala +++ b/src/dotty/tools/dotc/reporting/diagnostic/messages.scala @@ -184,7 +184,7 @@ object messages { val caseDef = s"case $pat$guard => $body" - hl"""|For each ${"case"} bound variable names have to be unique. In: + hl"""|For each ${"case"} bound variable names have to be unique. In: | |$caseDef | @@ -194,12 +194,14 @@ object messages { case class MissingIdent(tree: untpd.Ident, treeKind: String, name: String)(implicit ctx: Context) extends Message(6) { - val kind = "Missing Identifier" + val kind = "Unbound Identifier" val msg = em"not found: $treeKind$name" val explanation = { - hl"""|An identifier for `$treeKind$name` is missing. This means that something - |has either been misspelt or you're forgetting an import""" + hl"""|The identifier for `$treeKind$name` is not bound, that is, + |no declaration for this identifier can be found. + |That can happen for instance if $name or its declaration has either been + |misspelt, or if you're forgetting an import""" } } @@ -787,4 +789,106 @@ object messages { val msg = "unreachable code" val explanation = "" } + + case class SeqWildcardPatternPos()(implicit ctx: Context) extends Message(31) { + val kind = "Syntax" + val msg = "`_*' can be used only for last argument" + val explanation = { + val code = + """def sumOfTheFirstTwo(list: List[Int]): Int = list match { + | case List(first, second, x:_*) => first + second + | case _ => 0 + |}""" + hl"""|Sequence wildcard pattern is expected at the end of an argument list. + |This pattern matches any remaining elements in a sequence. + |Consider the following example: + | + |$code + | + |Calling: + | + |${"sumOfTheFirstTwo(List(1, 2, 10))"} + | + |would give 3 as a result""" + } + } + + case class IllegalStartOfSimplePattern()(implicit ctx: Context) extends Message(32) { + val kind = "Syntax" + val msg = "illegal start of simple pattern" + val explanation = { + val sipCode = + """def f(x: Int, y: Int) = x match { + | case `y` => ... + |} + """ + val constructorPatternsCode = + """case class Person(name: String, age: Int) + | + |def test(p: Person) = p match { + | case Person(name, age) => ... + |} + """ + val tupplePatternsCode = + """def swap(tuple: (String, Int)): (Int, String) = tuple match { + | case (text, number) => (number, text) + |} + """ + val patternSequencesCode = + """def getSecondValue(list: List[Int]): Int = list match { + | case List(_, second, x:_*) => second + | case _ => 0 + |}""" + hl"""|Simple patterns can be divided into several groups: + |- Variable Patterns: ${"case x => ..."}. + | It matches any value, and binds the variable name to that value. + | A special case is the wild-card pattern _ which is treated as if it was a fresh + | variable on each occurrence. + | + |- Typed Patterns: ${"case x: Int => ..."} or ${"case _: Int => ..."}. + | This pattern matches any value matched by the specified type; it binds the variable + | name to that value. + | + |- Literal Patterns: ${"case 123 => ..."} or ${"case 'A' => ..."}. + | This type of pattern matches any value that is equal to the specified literal. + | + |- Stable Identifier Patterns: + | + | $sipCode + | + | the match succeeds only if the x argument and the y argument of f are equal. + | + |- Constructor Patterns: + | + | $constructorPatternsCode + | + | The pattern binds all object's fields to the variable names (name and age, in this + | case). + | + |- Tuple Patterns: + | + | $tupplePatternsCode + | + | Calling: + | + | ${"""swap(("Luftballons", 99)"""} + | + | would give ${"""(99, "Luftballons")"""} as a result. + | + |- Pattern Sequences: + | + | $patternSequencesCode + | + | Calling: + | + | ${"getSecondValue(List(1, 10, 2))"} + | + | would give 10 as a result. + | This pattern is possible because a companion object for the List class has a method + | with the following signature: + | + | ${"def unapplySeq[A](x: List[A]): Some[List[A]]"} + |""" + } + } } diff --git a/src/dotty/tools/dotc/transform/ExplicitOuter.scala b/src/dotty/tools/dotc/transform/ExplicitOuter.scala index 3f235dca7..3fec47e9f 100644 --- a/src/dotty/tools/dotc/transform/ExplicitOuter.scala +++ b/src/dotty/tools/dotc/transform/ExplicitOuter.scala @@ -226,14 +226,18 @@ object ExplicitOuter { case ref: TermRef => if (ref.prefix ne NoPrefix) !ref.symbol.isStatic && isOuterRef(ref.prefix) - else if (ref.symbol is Hoistable) - // ref.symbol will be placed in enclosing class scope by LambdaLift, so it might need - // an outer path then. - isOuterSym(ref.symbol.owner.enclosingClass) - else - // ref.symbol will get a proxy in immediately enclosing class. If this properly - // contains the current class, it needs an outer path. - ctx.owner.enclosingClass.owner.enclosingClass.isContainedIn(ref.symbol.owner) + else ( + (ref.symbol is Hoistable) && + // ref.symbol will be placed in enclosing class scope by LambdaLift, so it might need + // an outer path then. + isOuterSym(ref.symbol.owner.enclosingClass) + || + // If not hoistable, ref.symbol will get a proxy in immediately enclosing class. If this properly + // contains the current class, it needs an outer path. + // If the symbol is hoistable, it might have free variables for which the same + // reasoning applies. See pos/i1664.scala + ctx.owner.enclosingClass.owner.enclosingClass.isContainedIn(ref.symbol.owner) + ) case _ => false } def hasOuterPrefix(tp: Type) = tp match { diff --git a/src/dotty/tools/dotc/typer/Namer.scala b/src/dotty/tools/dotc/typer/Namer.scala index dd7326fae..687de1e7a 100644 --- a/src/dotty/tools/dotc/typer/Namer.scala +++ b/src/dotty/tools/dotc/typer/Namer.scala @@ -656,6 +656,8 @@ class Namer { typer: Typer => * (1) It must be a class type with a stable prefix (@see checkClassTypeWithStablePrefix) * (2) If may not derive from itself * (3) Overriding type parameters must be correctly forwarded. (@see checkTypeParamOverride) + * (4) The class is not final + * (5) If the class is sealed, it is defined in the same compilation unit as the current class */ def checkedParentType(parent: untpd.Tree, paramAccessors: List[Symbol]): Type = { val ptype = parentType(parent)(ctx.superCallContext) @@ -674,7 +676,14 @@ class Namer { typer: Typer => } else if (!paramAccessors.forall(checkTypeParamOverride(pt, _))) defn.ObjectType - else pt + else { + val pclazz = pt.typeSymbol + if (pclazz.is(Final)) + ctx.error(em"cannot extend final $pclazz", cls.pos) + if (pclazz.is(Sealed) && pclazz.associatedFile != cls.associatedFile) + ctx.error(em"cannot extend sealed $pclazz in different compilation unit", cls.pos) + pt + } } } diff --git a/src/dotty/tools/dotc/typer/RefChecks.scala b/src/dotty/tools/dotc/typer/RefChecks.scala index 026015d1d..46bdbf3b3 100644 --- a/src/dotty/tools/dotc/typer/RefChecks.scala +++ b/src/dotty/tools/dotc/typer/RefChecks.scala @@ -72,8 +72,7 @@ object RefChecks { } } - /** Check that final and sealed restrictions on class parents - * and that self type of this class conforms to self types of parents. + /** Check that self type of this class conforms to self types of parents. * and required classes. */ private def checkParents(cls: Symbol)(implicit ctx: Context): Unit = cls.info match { @@ -83,14 +82,8 @@ object RefChecks { if (otherSelf.exists && !(cinfo.selfType <:< otherSelf)) ctx.error(ex"$category: self type ${cinfo.selfType} of $cls does not conform to self type $otherSelf of $relation ${other.classSymbol}", cls.pos) } - for (parent <- cinfo.classParents) { - val pclazz = parent.classSymbol - if (pclazz.is(Final)) - ctx.error(em"cannot extend final $pclazz", cls.pos) - if (pclazz.is(Sealed) && pclazz.associatedFile != cls.associatedFile) - ctx.error(em"cannot extend sealed $pclazz in different compilation unit", cls.pos) + for (parent <- cinfo.classParents) checkSelfConforms(parent, "illegal inheritance", "parent") - } for (reqd <- cinfo.givenSelfType.classSymbols) checkSelfConforms(reqd.typeRef, "missing requirement", "required") case _ => |