Skip to content

Commit d4a910a

Browse files
Merge branch 'master' into 9795
2 parents 875be9d + 001bfc3 commit d4a910a

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

48 files changed

+969
-604
lines changed

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

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1235,18 +1235,31 @@ object desugar {
12351235
rhsOK(rhs)
12361236
}
12371237

1238+
def checkOpaqueAlias(tree: MemberDef)(using Context): MemberDef =
1239+
def check(rhs: Tree): MemberDef = rhs match
1240+
case bounds: TypeBoundsTree if bounds.alias.isEmpty =>
1241+
report.error(i"opaque type must have a right-hand side", tree.srcPos)
1242+
tree.withMods(tree.mods.withoutFlags(Opaque))
1243+
case LambdaTypeTree(_, body) => check(body)
1244+
case _ => tree
1245+
if !tree.mods.is(Opaque) then tree
1246+
else tree match
1247+
case TypeDef(_, rhs) => check(rhs)
1248+
case _ => tree
1249+
12381250
/** Check that modifiers are legal for the definition `tree`.
12391251
* Right now, we only check for `opaque`. TODO: Move other modifier checks here.
12401252
*/
12411253
def checkModifiers(tree: Tree)(using Context): Tree = tree match {
12421254
case tree: MemberDef =>
12431255
var tested: MemberDef = tree
1244-
def checkApplicable(flag: Flag, test: MemberDefTest): Unit =
1256+
def checkApplicable(flag: Flag, test: MemberDefTest): MemberDef =
12451257
if (tested.mods.is(flag) && !test.applyOrElse(tree, (md: MemberDef) => false)) {
12461258
report.error(ModifierNotAllowedForDefinition(flag), tree.srcPos)
1247-
tested = tested.withMods(tested.mods.withoutFlags(flag))
1248-
}
1249-
checkApplicable(Opaque, legalOpaque)
1259+
tested.withMods(tested.mods.withoutFlags(flag))
1260+
} else tested
1261+
tested = checkOpaqueAlias(tested)
1262+
tested = checkApplicable(Opaque, legalOpaque)
12501263
tested
12511264
case _ =>
12521265
tree

compiler/src/dotty/tools/dotc/interactive/Completion.scala

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,11 @@ import dotty.tools.dotc.core.Names.{Name, TermName}
1212
import dotty.tools.dotc.core.NameKinds.SimpleNameKind
1313
import dotty.tools.dotc.core.NameOps._
1414
import dotty.tools.dotc.core.Scopes._
15-
import dotty.tools.dotc.core.Symbols.{Symbol, defn}
15+
import dotty.tools.dotc.core.Symbols.{NoSymbol, Symbol, defn, newSymbol}
1616
import dotty.tools.dotc.core.StdNames.nme
1717
import dotty.tools.dotc.core.SymDenotations.SymDenotation
1818
import dotty.tools.dotc.core.TypeError
19-
import dotty.tools.dotc.core.Types.{AppliedType, ExprType, MethodOrPoly, NameFilter, NoType, TermRef, Type}
19+
import dotty.tools.dotc.core.Types.{AppliedType, ExprType, MethodOrPoly, NameFilter, NoType, RefinedType, TermRef, Type, TypeProxy}
2020
import dotty.tools.dotc.parsing.Tokens
2121
import dotty.tools.dotc.util.Chars
2222
import dotty.tools.dotc.util.SourcePosition
@@ -474,6 +474,18 @@ object Completion {
474474
|| (mode.is(Mode.Type) && (sym.isType || sym.isStableMember)))
475475
)
476476

477+
private def extractRefinements(site: Type)(using Context): Seq[SingleDenotation] =
478+
site match
479+
case RefinedType(parent, name, info) =>
480+
val flags = info match
481+
case _: (ExprType | MethodOrPoly) => Method
482+
case _ => EmptyFlags
483+
val symbol = newSymbol(owner = NoSymbol, name, flags, info)
484+
val denot = SymDenotation(symbol, NoSymbol, name, flags, info)
485+
denot +: extractRefinements(parent)
486+
case tp: TypeProxy => extractRefinements(tp.underlying)
487+
case _ => List.empty
488+
477489
/** @param site The type to inspect.
478490
* @return The members of `site` that are accessible and pass the include filter.
479491
*/
@@ -488,10 +500,13 @@ object Completion {
488500
catch
489501
case ex: TypeError =>
490502

491-
site.memberDenots(completionsFilter, appendMemberSyms).collect {
503+
val members = site.memberDenots(completionsFilter, appendMemberSyms).collect {
492504
case mbr if include(mbr, mbr.name)
493505
&& mbr.symbol.isAccessibleFrom(site) => mbr
494506
}
507+
val refinements = extractRefinements(site).filter(mbr => include(mbr, mbr.name))
508+
509+
members ++ refinements
495510
}
496511

497512
/**
@@ -504,8 +519,7 @@ object Completion {
504519
private def implicitConversionTargets(qual: Tree)(using Context): Set[Type] = {
505520
val typer = ctx.typer
506521
val conversions = new typer.ImplicitSearch(defn.AnyType, qual, pos.span).allImplicits
507-
val convertedTrees = conversions.flatMap(typer.tryApplyingImplicitConversion(_, qual))
508-
val targets = convertedTrees.map(_.tpe.finalResultType)
522+
val targets = conversions.map(_.tree.tpe)
509523

510524
interactiv.println(i"implicit conversion targets considered: ${targets.toList}%, %")
511525
targets

compiler/src/dotty/tools/dotc/reporting/ErrorMessageID.scala

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,16 @@
11
package dotty.tools.dotc.reporting
22

3-
/** Unique IDs identifying the messages
3+
//////////////////////////////////////////////////////////////////////////
4+
// IMPORTANT //
5+
// Only add new IDs at end of the enumeration list and never remove IDs //
6+
//////////////////////////////////////////////////////////////////////////
7+
8+
/** Unique IDs identifying the messages, this will be used to reference documentation online.
9+
*
410
* @param isActive Whether or not the compile still emits this ErrorMessageID
511
**/
612
enum ErrorMessageID(val isActive: Boolean = true) extends java.lang.Enum[ErrorMessageID]:
713

8-
// IMPORTANT: Add new IDs only at the end and never remove IDs
9-
case LazyErrorId // // errorNumber: -2
1014
case NoExplanationID // errorNumber: -1
1115

1216
case EmptyCatchOrFinallyBlockID extends ErrorMessageID(isActive = false) // errorNumber: 0
@@ -180,12 +184,12 @@ enum ErrorMessageID(val isActive: Boolean = true) extends java.lang.Enum[ErrorMe
180184
case ImplicitSearchTooLargeID // errorNumber: 168
181185
case TargetNameOnTopLevelClassID // errorNumber: 169
182186

183-
def errorNumber = ordinal - 2
187+
def errorNumber = ordinal - 1
184188

185189
object ErrorMessageID:
186190
def fromErrorNumber(n: Int): Option[ErrorMessageID] =
187-
val enumId = n + 2
188-
if enumId >= 2 && enumId < ErrorMessageID.values.length then
191+
val enumId = n + 1
192+
if enumId >= 1 && enumId < ErrorMessageID.values.length then
189193
Some(fromOrdinal(enumId))
190194
else
191195
None

compiler/src/dotty/tools/dotc/reporting/Message.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ object Message {
4343
* Instead use the `persist` method to create an instance that does not keep a
4444
* reference to these contexts.
4545
*
46-
* @param errorId a unique id identifying the message, this will later be
46+
* @param errorId a unique id identifying the message, this will be
4747
* used to reference documentation online
4848
*/
4949
abstract class Message(val errorId: ErrorMessageID) { self =>

compiler/src/dotty/tools/dotc/transform/SymUtils.scala

Lines changed: 28 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -82,11 +82,26 @@ object SymUtils:
8282
* parameter section.
8383
*/
8484
def whyNotGenericProduct(using Context): String =
85+
/** for a case class, if it will have an anonymous mirror,
86+
* check that its constructor can be accessed
87+
* from the calling scope.
88+
*/
89+
def canAccessCtor: Boolean =
90+
def isAccessible(sym: Symbol): Boolean = ctx.owner.isContainedIn(sym)
91+
def isSub(sym: Symbol): Boolean = ctx.owner.ownersIterator.exists(_.derivesFrom(sym))
92+
val ctor = self.primaryConstructor
93+
(!ctor.isOneOf(Private | Protected) || isSub(self)) // we cant access the ctor because we do not extend cls
94+
&& (!ctor.privateWithin.exists || isAccessible(ctor.privateWithin)) // check scope is compatible
95+
96+
97+
def companionMirror = self.useCompanionAsProductMirror
8598
if (!self.is(CaseClass)) "it is not a case class"
8699
else if (self.is(Abstract)) "it is an abstract class"
87100
else if (self.primaryConstructor.info.paramInfoss.length != 1) "it takes more than one parameter list"
88101
else if (isDerivedValueClass(self)) "it is a value class"
102+
else if (!(companionMirror || canAccessCtor)) s"the constructor of $self is innaccessible from the calling scope."
89103
else ""
104+
end whyNotGenericProduct
90105

91106
def isGenericProduct(using Context): Boolean = whyNotGenericProduct.isEmpty
92107

@@ -120,6 +135,9 @@ object SymUtils:
120135
self.isOneOf(FinalOrInline, butNot = Mutable)
121136
&& (!self.is(Method) || self.is(Accessor))
122137

138+
def useCompanionAsProductMirror(using Context): Boolean =
139+
self.linkedClass.exists && !self.is(Scala2x) && !self.linkedClass.is(Case)
140+
123141
def useCompanionAsSumMirror(using Context): Boolean =
124142
def companionExtendsSum(using Context): Boolean =
125143
self.linkedClass.isSubClass(defn.Mirror_SumClass)
@@ -145,39 +163,39 @@ object SymUtils:
145163
* and also the location of the generated mirror.
146164
* - all of its children are generic products, singletons, or generic sums themselves.
147165
*/
148-
def whyNotGenericSum(declScope: Symbol)(using Context): String =
166+
def whyNotGenericSum(using Context): String =
149167
if (!self.is(Sealed))
150168
s"it is not a sealed ${self.kindString}"
151169
else if (!self.isOneOf(AbstractOrTrait))
152170
"it is not an abstract class"
153171
else {
154172
val children = self.children
155173
val companionMirror = self.useCompanionAsSumMirror
156-
assert(!(companionMirror && (declScope ne self.linkedClass)))
157174
def problem(child: Symbol) = {
158175

159176
def isAccessible(sym: Symbol): Boolean =
160-
(self.isContainedIn(sym) && (companionMirror || declScope.isContainedIn(sym)))
177+
(self.isContainedIn(sym) && (companionMirror || ctx.owner.isContainedIn(sym)))
161178
|| sym.is(Module) && isAccessible(sym.owner)
162179

163180
if (child == self) "it has anonymous or inaccessible subclasses"
164181
else if (!isAccessible(child.owner)) i"its child $child is not accessible"
165-
else if (!child.isClass) ""
182+
else if (!child.isClass) "" // its a singleton enum value
166183
else {
167184
val s = child.whyNotGenericProduct
168-
if (s.isEmpty) s
169-
else if (child.is(Sealed)) {
170-
val s = child.whyNotGenericSum(if child.useCompanionAsSumMirror then child.linkedClass else ctx.owner)
171-
if (s.isEmpty) s
185+
if s.isEmpty then s
186+
else if child.is(Sealed) then
187+
val s = child.whyNotGenericSum
188+
if s.isEmpty then s
172189
else i"its child $child is not a generic sum because $s"
173-
} else i"its child $child is not a generic product because $s"
190+
else
191+
i"its child $child is not a generic product because $s"
174192
}
175193
}
176194
if (children.isEmpty) "it does not have subclasses"
177195
else children.map(problem).find(!_.isEmpty).getOrElse("")
178196
}
179197

180-
def isGenericSum(declScope: Symbol)(using Context): Boolean = whyNotGenericSum(declScope).isEmpty
198+
def isGenericSum(using Context): Boolean = whyNotGenericSum.isEmpty
181199

182200
/** If this is a constructor, its owner: otherwise this. */
183201
final def skipConstructor(using Context): Symbol =

compiler/src/dotty/tools/dotc/transform/SyntheticMembers.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -594,9 +594,9 @@ class SyntheticMembers(thisPhase: DenotTransformer) {
594594
if (clazz.is(Module)) {
595595
if (clazz.is(Case)) makeSingletonMirror()
596596
else if (linked.isGenericProduct) makeProductMirror(linked)
597-
else if (linked.isGenericSum(clazz)) makeSumMirror(linked)
597+
else if (linked.isGenericSum) makeSumMirror(linked)
598598
else if (linked.is(Sealed))
599-
derive.println(i"$linked is not a sum because ${linked.whyNotGenericSum(clazz)}")
599+
derive.println(i"$linked is not a sum because ${linked.whyNotGenericSum}")
600600
}
601601
else if (impl.removeAttachment(ExtendsSingletonMirror).isDefined)
602602
makeSingletonMirror()

compiler/src/dotty/tools/dotc/transform/init/Errors.scala

Lines changed: 31 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -9,26 +9,21 @@ import util.SourcePosition
99
import Decorators._, printing.SyntaxHighlighting
1010
import Types._, Symbols._, Contexts._
1111

12-
object Errors {
13-
type Errors = Seq[Error]
14-
val empty: Errors = Nil
15-
16-
def show(errs: Errors)(using Context): String =
17-
errs.map(_.show).mkString(", ")
12+
import scala.collection.mutable
1813

14+
object Errors:
1915
sealed trait Error {
20-
def source: Tree
2116
def trace: Seq[Tree]
2217
def show(using Context): String
2318

24-
def issue(using Context): Unit =
25-
report.warning(show + stacktrace, source.srcPos)
19+
def pos(using Context): SourcePosition = trace.last.sourcePos
2620

27-
def toErrors: Errors = this :: Nil
21+
def issue(using Context): Unit =
22+
report.warning(show + stacktrace, this.pos)
2823

29-
def stacktrace(using Context): String = if (trace.isEmpty) "" else " Calling trace:\n" + {
30-
var last: String = ""
31-
val sb = new StringBuilder
24+
def stacktrace(using Context): String = if trace.isEmpty then "" else " Calling trace:\n" + {
25+
var lastLineNum = -1
26+
var lines: mutable.ArrayBuffer[String] = new mutable.ArrayBuffer
3227
trace.foreach { tree =>
3328
val pos = tree.sourcePos
3429
val prefix = "-> "
@@ -44,10 +39,16 @@ object Errors {
4439
positionMarker(pos)
4540
else ""
4641

47-
if (last != line) sb.append(prefix + line + "\n" + positionMarkerLine )
42+
// always use the more precise trace location
43+
if lastLineNum == pos.line then
44+
lines.dropRightInPlace(1)
4845

49-
last = line
46+
lines += (prefix + line + "\n" + positionMarkerLine)
47+
48+
lastLineNum = pos.line
5049
}
50+
val sb = new StringBuilder
51+
for line <- lines do sb.append(line)
5152
sb.toString
5253
}
5354

@@ -65,13 +66,6 @@ object Errors {
6566
s"$padding$carets\n"
6667
}
6768

68-
/** Flatten UnsafePromotion errors
69-
*/
70-
def flatten: Errors = this match {
71-
case unsafe: UnsafePromotion => unsafe.errors.flatMap(_.flatten)
72-
case _ => this :: Nil
73-
}
74-
7569
override def toString() = this.getClass.getName.nn
7670
}
7771

@@ -81,42 +75,37 @@ object Errors {
8175
def show(using Context): String =
8276
"Access non-initialized " + field.show + "."
8377

84-
override def issue(using Context): Unit =
85-
report.warning(show + stacktrace, field.srcPos)
78+
override def pos(using Context): SourcePosition = field.sourcePos
8679
}
8780

88-
/** Promote `this` under initialization to fully-initialized */
89-
case class PromoteError(msg: String, source: Tree, trace: Seq[Tree]) extends Error {
90-
def show(using Context): String = "Cannot prove that the value is fully initialized. " + msg + "."
81+
/** Promote a value under initialization to fully-initialized */
82+
case class PromoteError(msg: String, trace: Seq[Tree]) extends Error {
83+
def show(using Context): String = msg
9184
}
9285

93-
case class AccessCold(field: Symbol, source: Tree, trace: Seq[Tree]) extends Error {
86+
case class AccessCold(field: Symbol, trace: Seq[Tree]) extends Error {
9487
def show(using Context): String =
95-
"Access field " + source.show + " on a value with an unknown initialization status."
88+
"Access field on a value with an unknown initialization status."
9689
}
9790

98-
case class CallCold(meth: Symbol, source: Tree, trace: Seq[Tree]) extends Error {
91+
case class CallCold(meth: Symbol, trace: Seq[Tree]) extends Error {
9992
def show(using Context): String =
100-
"Call method " + source.show + " on a value with an unknown initialization" + "."
93+
"Call method on a value with an unknown initialization" + "."
10194
}
10295

103-
case class CallUnknown(meth: Symbol, source: Tree, trace: Seq[Tree]) extends Error {
96+
case class CallUnknown(meth: Symbol, trace: Seq[Tree]) extends Error {
10497
def show(using Context): String =
10598
val prefix = if meth.is(Flags.Method) then "Calling the external method " else "Accessing the external field"
10699
prefix + meth.show + " may cause initialization errors" + "."
107100
}
108101

109102
/** Promote a value under initialization to fully-initialized */
110-
case class UnsafePromotion(msg: String, source: Tree, trace: Seq[Tree], errors: Errors) extends Error {
111-
assert(errors.nonEmpty)
103+
case class UnsafePromotion(msg: String, trace: Seq[Tree], error: Error) extends Error {
112104
override def issue(using Context): Unit =
113-
report.warning(show, source.srcPos)
105+
report.warning(show, this.pos)
114106

115-
def show(using Context): String = {
116-
var index = 0
117-
"Cannot prove that the value is fully initialized. " + msg + ".\n" + stacktrace +
118-
"\nThe unsafe promotion may cause the following problem:\n" +
119-
errors.head.show + errors.head.stacktrace
120-
}
107+
def show(using Context): String =
108+
msg + stacktrace + "\n" +
109+
"Promoting the value to fully initialized failed due to the following problem:\n" +
110+
error.show + error.stacktrace
121111
}
122-
}

0 commit comments

Comments
 (0)