Skip to content

Commit aff93c3

Browse files
committed
Merge branch 'master' of github.com:EnzeXing/dotty into tests-for-dotty
Rebase
2 parents acdd93c + 7b0bdf2 commit aff93c3

File tree

216 files changed

+4677
-1539
lines changed

Some content is hidden

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

216 files changed

+4677
-1539
lines changed

.github/workflows/cla.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,5 @@ jobs:
66
steps:
77
- uses: actions/checkout@v2
88
- run: ./project/scripts/check-cla.sh
9+
env:
10+
AUTHOR: ${{ github.event.pull_request.user.login }}

.gitmodules

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -201,3 +201,6 @@
201201
[submodule "community-build/community-projects/fs2"]
202202
path = community-build/community-projects/fs2
203203
url = https://github.com/dotty-staging/fs2.git
204+
[submodule "community-build/community-projects/libretto"]
205+
path = community-build/community-projects/libretto
206+
url = https://github.com/dotty-staging/libretto.git
Submodule libretto added at d229f3c
Submodule munit updated 38 files

community-build/src/scala/dotty/communitybuild/projects.scala

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -691,6 +691,13 @@ object projects:
691691
dependencies = List(cats, catsEffect3, munitCatsEffect, scalacheckEffect, scodecBits)
692692
)
693693

694+
lazy val libretto = SbtCommunityProject(
695+
project = "libretto",
696+
sbtTestCommand = "core/test; examples/compile",
697+
sbtPublishCommand = "core/publishLocal; examples/publishLocal",
698+
dependencies = List(scalatest)
699+
)
700+
694701
end projects
695702

696703
def allProjects = List(
@@ -765,6 +772,7 @@ def allProjects = List(
765772
projects.munitCatsEffect,
766773
projects.scalacheckEffect,
767774
projects.fs2,
775+
projects.libretto,
768776
)
769777

770778
lazy val projectMap = allProjects.groupBy(_.project)

community-build/test/scala/dotty/communitybuild/CommunityBuildTest.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,7 @@ class CommunityBuildTestC extends CommunityBuildTest:
144144
@Test def fastparse = projects.fastparse.run()
145145
@Test def geny = projects.geny.run()
146146
@Test def intent = projects.intent.run()
147+
@Test def libretto = projects.libretto.run()
147148
@Test def minitest = projects.minitest.run()
148149
@Test def onnxScala = projects.onnxScala.run()
149150
@Test def oslib = projects.oslib.run()

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

Lines changed: 34 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1093,6 +1093,16 @@ object desugar {
10931093
case IdPattern(named, tpt) =>
10941094
derivedValDef(original, named, tpt, rhs, mods)
10951095
case _ =>
1096+
1097+
def filterWildcardGivenBinding(givenPat: Bind): Boolean =
1098+
givenPat.name != nme.WILDCARD
1099+
1100+
def errorOnGivenBinding(bind: Bind)(using Context): Boolean =
1101+
report.error(
1102+
em"""${hl("given")} patterns are not allowed in a ${hl("val")} definition,
1103+
|please bind to an identifier and use an alias given.""".stripMargin, bind)
1104+
false
1105+
10961106
def isTuplePattern(arity: Int): Boolean = pat match {
10971107
case Tuple(pats) if pats.size == arity =>
10981108
pats.forall(isVarPattern)
@@ -1108,13 +1118,23 @@ object desugar {
11081118
// - `pat` is a tuple of N variables or wildcard patterns like `(x1, x2, ..., xN)`
11091119
val tupleOptimizable = forallResults(rhs, isMatchingTuple)
11101120

1121+
val inAliasGenerator = original match
1122+
case _: GenAlias => true
1123+
case _ => false
1124+
11111125
val vars =
11121126
if (tupleOptimizable) // include `_`
1113-
pat match {
1114-
case Tuple(pats) =>
1115-
pats.map { case id: Ident => id -> TypeTree() }
1116-
}
1117-
else getVariables(pat) // no `_`
1127+
pat match
1128+
case Tuple(pats) => pats.map { case id: Ident => id -> TypeTree() }
1129+
else
1130+
getVariables(
1131+
tree = pat,
1132+
shouldAddGiven =
1133+
if inAliasGenerator then
1134+
filterWildcardGivenBinding
1135+
else
1136+
errorOnGivenBinding
1137+
) // no `_`
11181138

11191139
val ids = for ((named, _) <- vars) yield Ident(named.name)
11201140
val caseDef = CaseDef(pat, EmptyTree, makeTuple(ids))
@@ -1800,16 +1820,21 @@ object desugar {
18001820
/** Returns list of all pattern variables, possibly with their types,
18011821
* without duplicates
18021822
*/
1803-
private def getVariables(tree: Tree)(using Context): List[VarInfo] = {
1823+
private def getVariables(tree: Tree, shouldAddGiven: Context ?=> Bind => Boolean)(using Context): List[VarInfo] = {
18041824
val buf = ListBuffer[VarInfo]()
18051825
def seenName(name: Name) = buf exists (_._1.name == name)
18061826
def add(named: NameTree, t: Tree): Unit =
18071827
if (!seenName(named.name) && named.name.isTermName) buf += ((named, t))
18081828
def collect(tree: Tree): Unit = tree match {
1809-
case Bind(nme.WILDCARD, tree1) =>
1829+
case tree @ Bind(nme.WILDCARD, tree1) =>
1830+
if tree.mods.is(Given) then
1831+
val Typed(_, tpt) = tree1: @unchecked
1832+
if shouldAddGiven(tree) then
1833+
add(tree, tpt)
18101834
collect(tree1)
18111835
case tree @ Bind(_, Typed(tree1, tpt)) =>
1812-
add(tree, tpt)
1836+
if !(tree.mods.is(Given) && !shouldAddGiven(tree)) then
1837+
add(tree, tpt)
18131838
collect(tree1)
18141839
case tree @ Bind(_, tree1) =>
18151840
add(tree, TypeTree())
@@ -1827,7 +1852,7 @@ object desugar {
18271852
case SeqLiteral(elems, _) =>
18281853
elems foreach collect
18291854
case Alternative(trees) =>
1830-
for (tree <- trees; (vble, _) <- getVariables(tree))
1855+
for (tree <- trees; (vble, _) <- getVariables(tree, shouldAddGiven))
18311856
report.error(IllegalVariableInPatternAlternative(), vble.srcPos)
18321857
case Annotated(arg, _) =>
18331858
collect(arg)

compiler/src/dotty/tools/dotc/config/Config.scala

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,9 @@ object Config {
3434
*/
3535
inline val checkConstraintsPropagated = false
3636

37+
/** Check that constraint bounds do not contain wildcard types */
38+
inline val checkNoWildcardsInConstraint = false
39+
3740
/** If a constraint is over a type lambda `tl` and `tvar` is one of
3841
* the type variables associated with `tl` in the constraint, check
3942
* that the origin of `tvar` is a parameter of `tl`.

compiler/src/dotty/tools/dotc/config/Properties.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -84,11 +84,11 @@ trait PropertiesTrait {
8484

8585
/** Whether the current version of compiler is experimental
8686
*
87-
* 1. Snapshot and nightly releases are experimental.
87+
* 1. Snapshot, nightly releases and non-bootstrapped compiler are experimental.
8888
* 2. Features supported by experimental versions of the compiler:
8989
* - research plugins
9090
*/
91-
val experimental: Boolean = versionString.contains("SNAPSHOT") || versionString.contains("NIGHTLY")
91+
val experimental: Boolean = versionString.contains("SNAPSHOT") || versionString.contains("NIGHTLY") || versionString.contains("nonbootstrapped")
9292

9393
val copyrightString: String = scalaPropOrElse("copyright.string", "(c) 2002-2017 LAMP/EPFL")
9494

compiler/src/dotty/tools/dotc/core/ConstraintHandling.scala

Lines changed: 18 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import Flags._
1010
import config.Config
1111
import config.Printers.typr
1212
import reporting.trace
13+
import typer.ProtoTypes.newTypeVar
1314
import StdNames.tpnme
1415

1516
/** Methods for adding constraints and solving them.
@@ -78,22 +79,29 @@ trait ConstraintHandling {
7879
def fullBounds(param: TypeParamRef)(using Context): TypeBounds =
7980
nonParamBounds(param).derivedTypeBounds(fullLowerBound(param), fullUpperBound(param))
8081

81-
protected def addOneBound(param: TypeParamRef, bound: Type, isUpper: Boolean)(using Context): Boolean =
82+
/** If true, eliminate wildcards in bounds by avoidance, otherwise replace
83+
* them by fresh variables.
84+
*/
85+
protected def approximateWildcards: Boolean = true
86+
87+
protected def addOneBound(param: TypeParamRef, rawBound: Type, isUpper: Boolean)(using Context): Boolean =
8288
if !constraint.contains(param) then true
83-
else if !isUpper && param.occursIn(bound) then
89+
else if !isUpper && param.occursIn(rawBound) then
8490
// We don't allow recursive lower bounds when defining a type,
8591
// so we shouldn't allow them as constraints either.
8692
false
8793
else
94+
val dropWildcards = new AvoidWildcardsMap:
95+
if !isUpper then variance = -1
96+
override def mapWild(t: WildcardType) =
97+
if approximateWildcards then super.mapWild(t)
98+
else newTypeVar(apply(t.effectiveBounds).toBounds)
99+
val bound = dropWildcards(rawBound)
88100
val oldBounds @ TypeBounds(lo, hi) = constraint.nonParamBounds(param)
89101
val equalBounds = (if isUpper then lo else hi) eq bound
90-
if equalBounds
91-
&& !bound.existsPart(bp => bp.isInstanceOf[WildcardType] || (bp eq param))
92-
then
93-
// The narrowed bounds are equal and do not contain wildcards,
102+
if equalBounds && !bound.existsPart(_ eq param, stopAtStatic = true) then
103+
// The narrowed bounds are equal and not recursive,
94104
// so we can remove `param` from the constraint.
95-
// (Handling wildcards requires choosing a bound, but we don't know which
96-
// bound to choose here, this is handled in `ConstraintHandling#approximation`)
97105
constraint = constraint.replace(param, bound)
98106
true
99107
else
@@ -245,81 +253,11 @@ trait ConstraintHandling {
245253
* @pre `param` is in the constraint's domain.
246254
*/
247255
final def approximation(param: TypeParamRef, fromBelow: Boolean)(using Context): Type =
248-
249-
/** Substitute wildcards with fresh TypeParamRefs, to be compared with
250-
* other bound, so that they can be instantiated.
251-
*/
252-
object substWildcards extends TypeMap:
253-
override def stopAtStatic = true
254-
255-
var trackedPolis: List[PolyType] = Nil
256-
def apply(tp: Type) = tp match
257-
case tp: WildcardType =>
258-
val poly = PolyType(tpnme.EMPTY :: Nil)(pt => tp.bounds :: Nil, pt => defn.AnyType)
259-
trackedPolis = poly :: trackedPolis
260-
poly.paramRefs.head
261-
case _ =>
262-
mapOver(tp)
263-
end substWildcards
264-
265-
/** Replace TypeParamRefs substituted for wildcards by `substWildCards`
266-
* and any remaining wildcards by a safe approximation
267-
*/
268-
val replaceWildcards = new TypeMap:
269-
override def stopAtStatic = true
270-
271-
/** Try to instantiate a wildcard or TypeParamRef representing a wildcard
272-
* to a type that is known to conform to it.
273-
* This means:
274-
* If fromBelow is true, we minimize the type overall
275-
* Hence, if variance < 0, pick the maximal safe type: bounds.lo
276-
* (i.e. the whole bounds range is over the type).
277-
* If variance > 0, pick the minimal safe type: bounds.hi
278-
* (i.e. the whole bounds range is under the type).
279-
* If variance == 0, pick bounds.lo anyway (this is arbitrary but in line with
280-
* the principle that we pick the smaller type when in doubt).
281-
* If fromBelow is false, we maximize the type overall and reverse the bounds
282-
* If variance != 0. For variance == 0, we still minimize.
283-
* In summary we pick the bound given by this table:
284-
*
285-
* variance | -1 0 1
286-
* ------------------------
287-
* from below | lo lo hi
288-
* from above | hi lo lo
289-
*/
290-
def pickOneBound(bounds: TypeBounds) =
291-
if variance == 0 || fromBelow == (variance < 0) then bounds.lo
292-
else bounds.hi
293-
294-
def apply(tp: Type) = mapOver {
295-
tp match
296-
case tp: WildcardType =>
297-
pickOneBound(tp.bounds)
298-
case tp: TypeParamRef if substWildcards.trackedPolis.contains(tp.binder) =>
299-
pickOneBound(fullBounds(tp))
300-
case _ => tp
301-
}
302-
end replaceWildcards
303-
304256
constraint.entry(param) match
305257
case entry: TypeBounds =>
306258
val useLowerBound = fromBelow || param.occursIn(entry.hi)
307-
val rawBound = if useLowerBound then fullLowerBound(param) else fullUpperBound(param)
308-
val bound = substWildcards(rawBound)
309-
val inst =
310-
if bound eq rawBound then bound
311-
else
312-
// Get rid of wildcards by mapping them to fresh TypeParamRefs
313-
// with constraints derived from comparing both bounds, and then
314-
// instantiating. See pos/i10161.scala for a test where this matters.
315-
val saved = constraint
316-
try
317-
for poly <- substWildcards.trackedPolis do addToConstraint(poly, Nil)
318-
if useLowerBound then bound <:< fullUpperBound(param)
319-
else fullLowerBound(param) <:< bound
320-
replaceWildcards(bound)
321-
finally constraint = saved
322-
typr.println(s"approx ${param.show}, from below = $fromBelow, bound = ${bound.show}, inst = ${inst.show}")
259+
val inst = if useLowerBound then fullLowerBound(param) else fullUpperBound(param)
260+
typr.println(s"approx ${param.show}, from below = $fromBelow, inst = ${inst.show}")
323261
inst
324262
case inst =>
325263
assert(inst.exists, i"param = $param\nconstraint = $constraint")

compiler/src/dotty/tools/dotc/core/Definitions.scala

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -455,8 +455,9 @@ class Definitions {
455455
ScalaPackageClass, tpnme.Nothing, AbstractFinal, List(AnyType))
456456
def NothingType: TypeRef = NothingClass.typeRef
457457
@tu lazy val NullClass: ClassSymbol = {
458-
val parent = if ctx.explicitNulls then AnyType else ObjectType
459-
enterCompleteClassSymbol(ScalaPackageClass, tpnme.Null, AbstractFinal, parent :: Nil)
458+
// When explicit-nulls is enabled, Null becomes a direct subtype of Any and Matchable
459+
val parents = if ctx.explicitNulls then AnyType :: MatchableType :: Nil else ObjectType :: Nil
460+
enterCompleteClassSymbol(ScalaPackageClass, tpnme.Null, AbstractFinal, parents)
460461
}
461462
def NullType: TypeRef = NullClass.typeRef
462463

compiler/src/dotty/tools/dotc/core/NamerOps.scala

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,15 +11,14 @@ import ast.untpd
1111
/** Operations that are shared between Namer and TreeUnpickler */
1212
object NamerOps:
1313

14-
/** The given type, unless `sym` is a constructor, in which case the
15-
* type of the constructed instance is returned
14+
/** The type of the constructed instance is returned
15+
*
16+
* @param ctor the constructor
1617
*/
17-
def effectiveResultType(sym: Symbol, paramss: List[List[Symbol]], givenTp: Type)(using Context): Type =
18-
if sym.name == nme.CONSTRUCTOR then
19-
paramss match
20-
case TypeSymbols(tparams) :: _ => sym.owner.typeRef.appliedTo(tparams.map(_.typeRef))
21-
case _ => sym.owner.typeRef
22-
else givenTp
18+
def effectiveResultType(ctor: Symbol, paramss: List[List[Symbol]])(using Context): Type =
19+
paramss match
20+
case TypeSymbols(tparams) :: _ => ctor.owner.typeRef.appliedTo(tparams.map(_.typeRef))
21+
case _ => ctor.owner.typeRef
2322

2423
/** if isConstructor, make sure it has one leading non-implicit parameter list */
2524
def normalizeIfConstructor(paramss: List[List[Symbol]], isConstructor: Boolean)(using Context): List[List[Symbol]] =

compiler/src/dotty/tools/dotc/core/OrderingConstraint.scala

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -280,9 +280,11 @@ class OrderingConstraint(private val boundsMap: ParamBounds,
280280
var current = this
281281
val todos = new mutable.ListBuffer[(OrderingConstraint, TypeParamRef) => OrderingConstraint]
282282
var i = 0
283+
val dropWildcards = AvoidWildcardsMap()
283284
while (i < poly.paramNames.length) {
284285
val param = poly.paramRefs(i)
285-
val stripped = stripParams(nonParamBounds(param), todos, isUpper = true)
286+
val bounds = dropWildcards(nonParamBounds(param))
287+
val stripped = stripParams(bounds, todos, isUpper = true)
286288
current = updateEntry(current, param, stripped)
287289
while todos.nonEmpty do
288290
current = todos.head(current, param)
@@ -309,8 +311,11 @@ class OrderingConstraint(private val boundsMap: ParamBounds,
309311
val r1 = recur(tp.tp1, fromBelow)
310312
val r2 = recur(tp.tp2, fromBelow)
311313
if (r1 eq tp.tp1) && (r2 eq tp.tp2) then tp
312-
else if tp.isAnd then r1 & r2
313-
else r1 | r2
314+
else tp.match
315+
case tp: OrType =>
316+
TypeComparer.lub(r1, r2, isSoft = tp.isSoft)
317+
case _ =>
318+
r1 & r2
314319
case tp: TypeParamRef =>
315320
if tp eq param then
316321
if fromBelow then defn.NothingType else defn.AnyType
@@ -373,6 +378,7 @@ class OrderingConstraint(private val boundsMap: ParamBounds,
373378
Nil
374379

375380
private def updateEntry(current: This, param: TypeParamRef, tp: Type)(using Context): This = {
381+
if Config.checkNoWildcardsInConstraint then assert(!tp.containsWildcardTypes)
376382
var current1 = boundsLens.update(this, current, param, tp)
377383
tp match {
378384
case TypeBounds(lo, hi) =>

0 commit comments

Comments
 (0)