aboutsummaryrefslogtreecommitdiff
path: root/src/dotty/tools/dotc
diff options
context:
space:
mode:
authorMartin Odersky <odersky@gmail.com>2015-12-30 16:10:13 +0100
committerGuillaume Martres <smarter@ubuntu.com>2016-01-18 16:49:16 +0100
commit39ca54fcbe21df0fd277ab9734a032d71027fa4c (patch)
treed1ad29ce0293a05daab5e82d94dad1e881295605 /src/dotty/tools/dotc
parentc0b545be494bc53f9839c8301cdca71edeb620c7 (diff)
downloaddotty-39ca54fcbe21df0fd277ab9734a032d71027fa4c.tar.gz
dotty-39ca54fcbe21df0fd277ab9734a032d71027fa4c.tar.bz2
dotty-39ca54fcbe21df0fd277ab9734a032d71027fa4c.zip
Check bounds everywhere
Previously, bounds of a TypeDef tree were not checked. We now make sure bounds are checked everywhere in PostTyper. The previous partial check in Applications gets removed (it was not complete even for TypeApplications because sometimes bounds were not yet known when the test was performed.)
Diffstat (limited to 'src/dotty/tools/dotc')
-rw-r--r--src/dotty/tools/dotc/transform/PostTyper.scala51
-rw-r--r--src/dotty/tools/dotc/typer/Applications.scala1
-rw-r--r--src/dotty/tools/dotc/typer/Checking.scala12
3 files changed, 35 insertions, 29 deletions
diff --git a/src/dotty/tools/dotc/transform/PostTyper.scala b/src/dotty/tools/dotc/transform/PostTyper.scala
index edf97f5b8..f9862bb95 100644
--- a/src/dotty/tools/dotc/transform/PostTyper.scala
+++ b/src/dotty/tools/dotc/transform/PostTyper.scala
@@ -68,7 +68,7 @@ class PostTyper extends MacroTransform with IdentityDenotTransformer { thisTran
// TODO fill in
}
- /** Check bounds of AppliedTypeTrees and TypeApplys.
+ /** Check bounds of AppliedTypeTrees.
* Replace type trees with TypeTree nodes.
* Replace constant expressions with Literal nodes.
* Note: Demanding idempotency instead of purity in literalize is strictly speaking too loose.
@@ -97,29 +97,17 @@ class PostTyper extends MacroTransform with IdentityDenotTransformer { thisTran
* Revisit this issue once we have implemented `inline`. Then we can demand
* purity of the prefix unless the selection goes to an inline val.
*/
- private def normalizeTree(tree: Tree)(implicit ctx: Context): Tree = {
- def literalize(tp: Type): Tree = tp.widenTermRefExpr match {
- case ConstantType(value) if isIdempotentExpr(tree) => Literal(value)
- case _ => tree
- }
- def norm(tree: Tree) =
- if (tree.isType) TypeTree(tree.tpe).withPos(tree.pos)
- else literalize(tree.tpe)
- tree match {
- case tree: TypeTree =>
- tree
- case AppliedTypeTree(tycon, args) =>
- val tparams = tycon.tpe.typeSymbol.typeParams
- val bounds = tparams.map(tparam =>
- tparam.info.asSeenFrom(tycon.tpe.normalizedPrefix, tparam.owner.owner).bounds)
- Checking.checkBounds(args, bounds, _.substDealias(tparams, _))
- norm(tree)
- case TypeApply(fn, args) =>
- Checking.checkBounds(args, fn.tpe.widen.asInstanceOf[PolyType])
- norm(tree)
- case _ =>
- norm(tree)
- }
+ private def normalizeTree(tree: Tree)(implicit ctx: Context): Tree = tree match {
+ case tree: TypeTree => tree
+ case _ =>
+ if (tree.isType) {
+ Checking.boundsChecker.traverse(tree)
+ TypeTree(tree.tpe).withPos(tree.pos)
+ }
+ else tree.tpe.widenTermRefExpr match {
+ case ConstantType(value) if isIdempotentExpr(tree) => Literal(value)
+ case _ => tree
+ }
}
class PostTyperTransformer extends Transformer {
@@ -161,10 +149,16 @@ class PostTyper extends MacroTransform with IdentityDenotTransformer { thisTran
}
case tree: Select =>
transformSelect(paramFwd.adaptRef(tree), Nil)
- case tree @ TypeApply(sel: Select, args) =>
- val args1 = transform(args)
- val sel1 = transformSelect(sel, args1)
- if (superAcc.isProtectedAccessor(sel1)) sel1 else cpy.TypeApply(tree)(sel1, args1)
+ case tree @ TypeApply(fn, args) =>
+ Checking.checkBounds(args, fn.tpe.widen.asInstanceOf[PolyType])
+ fn match {
+ case sel: Select =>
+ val args1 = transform(args)
+ val sel1 = transformSelect(sel, args1)
+ if (superAcc.isProtectedAccessor(sel1)) sel1 else cpy.TypeApply(tree)(sel1, args1)
+ case _ =>
+ super.transform(tree)
+ }
case tree @ Assign(sel: Select, _) =>
superAcc.transformAssign(super.transform(tree))
case tree: Template =>
@@ -186,6 +180,7 @@ class PostTyper extends MacroTransform with IdentityDenotTransformer { thisTran
val tree1 =
if (sym.isClass) tree
else {
+ Checking.boundsChecker.traverse(tree.rhs)
cpy.TypeDef(tree)(rhs = TypeTree(tree.symbol.info))
}
super.transform(tree1)
diff --git a/src/dotty/tools/dotc/typer/Applications.scala b/src/dotty/tools/dotc/typer/Applications.scala
index b3cda20b8..649b8088f 100644
--- a/src/dotty/tools/dotc/typer/Applications.scala
+++ b/src/dotty/tools/dotc/typer/Applications.scala
@@ -607,7 +607,6 @@ trait Applications extends Compatibility { self: Typer =>
case pt: PolyType =>
if (typedArgs.length <= pt.paramBounds.length)
typedArgs = typedArgs.zipWithConserve(pt.paramBounds)(adaptTypeArg)
- Checking.checkBounds(typedArgs, pt)
case _ =>
}
assignType(cpy.TypeApply(tree)(typedFn, typedArgs), typedFn, typedArgs)
diff --git a/src/dotty/tools/dotc/typer/Checking.scala b/src/dotty/tools/dotc/typer/Checking.scala
index 6ded7c109..3e829eb50 100644
--- a/src/dotty/tools/dotc/typer/Checking.scala
+++ b/src/dotty/tools/dotc/typer/Checking.scala
@@ -48,6 +48,18 @@ object Checking {
def checkBounds(args: List[tpd.Tree], poly: PolyType)(implicit ctx: Context): Unit =
checkBounds(args, poly.paramBounds, _.substParams(poly, _))
+ /** Check all AppliedTypeTree nodes in this tree for legal bounds */
+ val boundsChecker = new TreeTraverser {
+ def traverse(tree: Tree)(implicit ctx: Context) = tree match {
+ case AppliedTypeTree(tycon, args) =>
+ val tparams = tycon.tpe.typeSymbol.typeParams
+ val bounds = tparams.map(tparam =>
+ tparam.info.asSeenFrom(tycon.tpe.normalizedPrefix, tparam.owner.owner).bounds)
+ checkBounds(args, bounds, _.substDealias(tparams, _))
+ case _ => traverseChildren(tree)
+ }
+ }
+
/** Check that `tp` refers to a nonAbstract class
* and that the instance conforms to the self type of the created class.
*/