aboutsummaryrefslogtreecommitdiff
path: root/src/dotty
diff options
context:
space:
mode:
Diffstat (limited to 'src/dotty')
-rw-r--r--src/dotty/tools/dotc/ast/CheckTrees.scala5
-rw-r--r--src/dotty/tools/dotc/ast/Trees.scala2
-rw-r--r--src/dotty/tools/dotc/ast/tpd.scala222
-rw-r--r--src/dotty/tools/dotc/core/Contexts.scala13
-rw-r--r--src/dotty/tools/dotc/core/TypeComparer.scala20
-rw-r--r--src/dotty/tools/dotc/core/Types.scala2
-rw-r--r--src/dotty/tools/dotc/core/pickling/UnPickler.scala4
-rw-r--r--src/dotty/tools/dotc/printing/RefinedPrinter.scala4
-rw-r--r--src/dotty/tools/dotc/typer/Applications.scala43
-rw-r--r--src/dotty/tools/dotc/typer/Checking.scala141
-rw-r--r--src/dotty/tools/dotc/typer/ErrorReporting.scala2
-rw-r--r--src/dotty/tools/dotc/typer/Implicits.scala2
-rw-r--r--src/dotty/tools/dotc/typer/Inferencing.scala491
-rw-r--r--src/dotty/tools/dotc/typer/Namer.scala22
-rw-r--r--src/dotty/tools/dotc/typer/ProtoTypes.scala384
-rw-r--r--src/dotty/tools/dotc/typer/TypeAssigner.scala334
-rw-r--r--src/dotty/tools/dotc/typer/Typer.scala286
17 files changed, 1068 insertions, 909 deletions
diff --git a/src/dotty/tools/dotc/ast/CheckTrees.scala b/src/dotty/tools/dotc/ast/CheckTrees.scala
index 1fae0a1f1..832544706 100644
--- a/src/dotty/tools/dotc/ast/CheckTrees.scala
+++ b/src/dotty/tools/dotc/ast/CheckTrees.scala
@@ -6,6 +6,7 @@ import core._
import util.Positions._, Types._, Contexts._, Constants._, Names._, Flags._
import SymDenotations._, Symbols._, StdNames._, Annotations._, Trees._
+// TODO: revise, integrate in a checking phase.
object CheckTrees {
import tpd._
@@ -19,7 +20,7 @@ object CheckTrees {
def escapingRefs(block: Block)(implicit ctx: Context): collection.Set[NamedType] = {
var hoisted: Set[Symbol] = Set()
- lazy val locals = localSyms(block.stats).toSet
+ lazy val locals = ctx.typeAssigner.localSyms(block.stats).toSet
def isLocal(sym: Symbol): Boolean =
(locals contains sym) && !isHoistableClass(sym)
def isHoistableClass(sym: Symbol) =
@@ -177,7 +178,7 @@ object CheckTrees {
checkRefinements(forbidden - rsym, rs1)
case nil =>
}
- checkRefinements(localSyms(refinements).toSet, refinements)
+ checkRefinements(ctx.typeAssigner.localSyms(refinements).toSet, refinements)
case AppliedTypeTree(tpt, args) =>
check(tpt.isValueType)
val tparams = tpt.tpe.typeParams
diff --git a/src/dotty/tools/dotc/ast/Trees.scala b/src/dotty/tools/dotc/ast/Trees.scala
index 17e2c3817..e0e64f06a 100644
--- a/src/dotty/tools/dotc/ast/Trees.scala
+++ b/src/dotty/tools/dotc/ast/Trees.scala
@@ -644,7 +644,7 @@ object Trees {
/** >: lo <: hi */
case class TypeBoundsTree[-T >: Untyped] private[ast] (lo: Tree[T], hi: Tree[T])
- extends Tree[T] {
+ extends TypTree[T] {
type ThisTree[-T >: Untyped] = TypeBoundsTree[T]
}
diff --git a/src/dotty/tools/dotc/ast/tpd.scala b/src/dotty/tools/dotc/ast/tpd.scala
index 95f5b49be..bda90b9e6 100644
--- a/src/dotty/tools/dotc/ast/tpd.scala
+++ b/src/dotty/tools/dotc/ast/tpd.scala
@@ -11,133 +11,78 @@ import config.Printers._
/** Some creators for typed trees */
object tpd extends Trees.Instance[Type] with TypedTreeInfo {
+ private def ta(implicit ctx: Context) = ctx.typeAssigner
+
def Modifiers(sym: Symbol)(implicit ctx: Context): Modifiers = Modifiers(
sym.flags & ModifierFlags,
if (sym.privateWithin.exists) sym.privateWithin.asType.name else tpnme.EMPTY,
sym.annotations map (_.tree))
def Ident(tp: NamedType)(implicit ctx: Context): Ident =
- underlyingIfRepeated(untpd.Ident(tp.name) withType tp).checked
+ ta.assignType(untpd.Ident(tp.name), tp)
def Select(qualifier: Tree, name: Name)(implicit ctx: Context): Select =
- untpd.Select(qualifier, name).withType(qualifier.tpe select name)
+ ta.assignType(untpd.Select(qualifier, name), qualifier)
def Select(qualifier: Tree, tp: NamedType)(implicit ctx: Context): Select =
- untpd.Select(qualifier, tp.name).withType(tp).checked
+ untpd.Select(qualifier, tp.name).withType(tp)
def SelectWithSig(qualifier: Tree, name: Name, sig: Signature)(implicit ctx: Context) =
untpd.SelectWithSig(qualifier, name, sig)
.withType(TermRef.withSig(qualifier.tpe, name.asTermName, sig))
+ def SelectFromTypeTree(qualifier: Tree, name: Name)(implicit ctx: Context): SelectFromTypeTree =
+ ta.assignType(untpd.SelectFromTypeTree(qualifier, name), qualifier)
+
+ def SelectFromTypeTree(qualifier: Tree, tp: NamedType)(implicit ctx: Context): SelectFromTypeTree =
+ untpd.SelectFromTypeTree(qualifier, tp.name).withType(tp)
+
def This(cls: ClassSymbol)(implicit ctx: Context): This =
- untpd.This(cls.name).withType(cls.thisType).checked
-
- def Super(qual: Tree, mix: TypeName)(implicit ctx: Context): Super = {
- val owntype =
- if (mix.isEmpty) ctx.typeComparer.glb(qual.tpe.parents)
- else {
- val mixParents = qual.tpe.parents filter (_.name == mix)
- check(mixParents.length == 1)
- mixParents.head
- }
- untpd.Super(qual, mix).withType(SuperType(qual.tpe, owntype)).checked
- }
+ ta.assignType(untpd.This(cls.name))
- def Apply(fn: Tree, args: List[Tree])(implicit ctx: Context): Apply = {
- val owntype = fn.tpe.widen match {
- case fntpe @ MethodType(pnames, ptypes) =>
- check(sameLength(ptypes, args), s"${fn.show}: ${fntpe.show} to ${args.map(_.show).mkString(", ")}")
- fntpe.instantiate(args map (_.tpe))
- case t =>
- check(false, s"fn = $fn, args = $args, tp = $t")
- ErrorType
- }
- untpd.Apply(fn, args).withType(owntype).checked
- }
+ def Super(qual: Tree, mix: TypeName, inConstrCall: Boolean)(implicit ctx: Context): Super =
+ ta.assignType(untpd.Super(qual, mix), qual, inConstrCall)
- def TypeApply(fn: Tree, args: List[Tree])(implicit ctx: Context): TypeApply = {
- val owntype = fn.tpe.widen match {
- case fntpe @ PolyType(pnames) =>
- check(sameLength(pnames, args))
- fntpe.instantiate(args map (_.tpe))
- case t =>
- check(false, s"bad type: $t")
- ErrorType
- }
- untpd.TypeApply(fn, args).withType(owntype).checked
- }
+ def Apply(fn: Tree, args: List[Tree])(implicit ctx: Context): Apply =
+ ta.assignType(untpd.Apply(fn, args), fn, args)
+
+ def TypeApply(fn: Tree, args: List[Tree])(implicit ctx: Context): TypeApply =
+ ta.assignType(untpd.TypeApply(fn, args), fn, args)
def Literal(const: Constant)(implicit ctx: Context): Literal =
- untpd.Literal(const).withType(const.tpe).checked
+ ta.assignType(untpd.Literal(const))
def unitLiteral(implicit ctx: Context): Literal =
Literal(Constant(()))
def New(tpt: Tree)(implicit ctx: Context): New =
- untpd.New(tpt).withType(tpt.tpe).checked
+ ta.assignType(untpd.New(tpt), tpt)
def New(tp: Type)(implicit ctx: Context): New = New(TypeTree(tp))
def Pair(left: Tree, right: Tree)(implicit ctx: Context): Pair =
- untpd.Pair(left, right).withType(defn.PairType.appliedTo(left.tpe, right.tpe)).checked
+ ta.assignType(untpd.Pair(left, right), left, right)
def Typed(expr: Tree, tpt: Tree)(implicit ctx: Context): Typed =
- untpd.Typed(expr, tpt).withType(tpt.tpe).checked
+ ta.assignType(untpd.Typed(expr, tpt), tpt)
def NamedArg(name: Name, arg: Tree)(implicit ctx: Context) =
- untpd.NamedArg(name, arg).withType(arg.tpe).checked
+ ta.assignType(untpd.NamedArg(name, arg), arg)
def Assign(lhs: Tree, rhs: Tree)(implicit ctx: Context): Assign =
- untpd.Assign(lhs, rhs).withType(defn.UnitType).checked
+ ta.assignType(untpd.Assign(lhs, rhs))
def Block(stats: List[Tree], expr: Tree)(implicit ctx: Context): Block =
- untpd.Block(stats, expr).withType(avoid(expr.tpe, localSyms(stats))).checked
-
- def avoid(tp: Type, syms: => List[Symbol])(implicit ctx: Context): Type = {
- val widenMap = new TypeMap {
- lazy val forbidden = syms.toSet
- def toAvoid(tp: Type): Boolean = tp match {
- case tp: TermRef =>
- val sym = tp.symbol
- sym.exists && (
- sym.owner.isTerm && (forbidden contains sym)
- || !(sym.owner is Package) && toAvoid(tp.prefix)
- )
- case _ =>
- false
- }
- def apply(tp: Type) = tp match {
- case tp: TermRef if toAvoid(tp) && variance > 0 =>
- apply(tp.info)
- case tp: TypeRef if toAvoid(tp.prefix) =>
- tp.info match {
- case TypeAlias(ref) => apply(ref)
- case _ => mapOver(tp)
- }
- case tp: RefinedType =>
- val tp1 @ RefinedType(parent1, _) = mapOver(tp)
- if (tp1.refinedInfo existsPart toAvoid) {
- typr.println(s"dropping refinement from $tp1")
- parent1
- }
- else tp1
- case _ =>
- mapOver(tp)
- }
- }
- widenMap(tp)
- }
+ ta.assignType(untpd.Block(stats, expr), stats, expr)
def maybeBlock(stats: List[Tree], expr: Tree)(implicit ctx: Context): Tree =
if (stats.isEmpty) expr else Block(stats, expr)
def If(cond: Tree, thenp: Tree, elsep: Tree)(implicit ctx: Context): If =
- untpd.If(cond, thenp, elsep).withType(thenp.tpe | elsep.tpe).checked
+ ta.assignType(untpd.If(cond, thenp, elsep), thenp, elsep)
- def Closure(env: List[Tree], meth: Tree, tpt: Tree)(implicit ctx: Context): Closure = {
- val ownType = if (tpt.isEmpty) meth.tpe.widen.toFunctionType else tpt.tpe
- untpd.Closure(env, meth, tpt).withType(ownType).checked
- }
+ def Closure(env: List[Tree], meth: Tree, tpt: Tree)(implicit ctx: Context): Closure =
+ ta.assignType(untpd.Closure(env, meth, tpt), meth, tpt)
/** A function def
*
@@ -157,37 +102,30 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
Closure(Nil, Ident(TermRef(NoPrefix, meth)), targetTpt))
}
- def Match(selector: Tree, cases: List[CaseDef])(implicit ctx: Context): Match =
- untpd.Match(selector, cases).withType(ctx.typeComparer.lub(cases.tpes)).checked
-
def CaseDef(pat: Tree, guard: Tree, body: Tree)(implicit ctx: Context): CaseDef =
- untpd.CaseDef(pat, guard, body).withType(body.tpe).checked
+ ta.assignType(untpd.CaseDef(pat, guard, body), body)
+
+ def Match(selector: Tree, cases: List[CaseDef])(implicit ctx: Context): Match =
+ ta.assignType(untpd.Match(selector, cases), cases)
def Return(expr: Tree, from: Tree)(implicit ctx: Context): Return =
- untpd.Return(expr, from).withType(defn.NothingType).checked
+ ta.assignType(untpd.Return(expr, from))
def Try(block: Tree, handler: Tree, finalizer: Tree)(implicit ctx: Context): Try =
- untpd.Try(block, handler, finalizer).withType(block.tpe | handler.tpe).checked
+ ta.assignType(untpd.Try(block, handler, finalizer), block, handler)
def Throw(expr: Tree)(implicit ctx: Context): Throw =
- untpd.Throw(expr).withType(defn.NothingType).checked
+ ta.assignType(untpd.Throw(expr))
def SeqLiteral(elems: List[Tree])(implicit ctx: Context): SeqLiteral =
- untpd.SeqLiteral(elems)
- .withType(defn.SeqClass.typeRef.appliedTo(ctx.typeComparer.lub(elems.tpes)))
- .checked
-
- def SeqLiteral(tpe: Type, elems: List[Tree])(implicit ctx: Context): SeqLiteral = {
- val untpdSeqLit =
- if (tpe derivesFrom defn.SeqClass) untpd.SeqLiteral(elems)
- else untpd.JavaSeqLiteral(elems)
- untpdSeqLit.withType(tpe).checked
- }
+ ta.assignType(untpd.SeqLiteral(elems), elems)
+
+ def SeqLiteral(tpe: Type, elems: List[Tree])(implicit ctx: Context): SeqLiteral =
+ if (tpe derivesFrom defn.SeqClass) SeqLiteral(elems) else JavaSeqLiteral(elems)
def JavaSeqLiteral(elems: List[Tree])(implicit ctx: Context): SeqLiteral =
new untpd.JavaSeqLiteral(elems)
.withType(defn.ArrayClass.typeRef.appliedTo(ctx.typeComparer.lub(elems.tpes)))
- .checked
def TypeTree(original: Tree)(implicit ctx: Context): TypeTree =
TypeTree(original.tpe, original)
@@ -196,61 +134,41 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
untpd.TypeTree(original).withType(tp).checked
def SingletonTypeTree(ref: Tree)(implicit ctx: Context): SingletonTypeTree =
- untpd.SingletonTypeTree(ref).withType(ref.tpe).checked
-
- def SelectFromTypeTree(qualifier: Tree, name: Name)(implicit ctx: Context): SelectFromTypeTree =
- untpd.SelectFromTypeTree(qualifier, name).withType(qualifier.tpe select name).checked
-
- def SelectFromTypeTree(qualifier: Tree, tp: NamedType)(implicit ctx: Context): SelectFromTypeTree =
- untpd.SelectFromTypeTree(qualifier, tp.name).withType(tp).checked
+ ta.assignType(untpd.SingletonTypeTree(ref), ref)
def AndTypeTree(left: Tree, right: Tree)(implicit ctx: Context): AndTypeTree =
- untpd.AndTypeTree(left, right).withType(left.tpe & right.tpe).checked
+ ta.assignType(untpd.AndTypeTree(left, right), left, right)
def OrTypeTree(left: Tree, right: Tree)(implicit ctx: Context): OrTypeTree =
- untpd.OrTypeTree(left, right).withType(left.tpe | right.tpe).checked
+ ta.assignType(untpd.OrTypeTree(left, right), left, right)
- def RefinedTypeTree(tpt: Tree, refinements: List[Tree])(implicit ctx: Context): RefinedTypeTree = {
- def refineType(tp: Type, refinement: Symbol): Type =
- RefinedType(tp, refinement.name, refinement.info)
- untpd.RefinedTypeTree(tpt, refinements)
- .withType((tpt.tpe /: (refinements map (_.symbol)))(refineType)).checked
- }
-
- def refineType(tp: Type, refinement: Symbol)(implicit ctx: Context): Type =
- RefinedType(tp, refinement.name, refinement.info)
+ // RefinedTypeTree is missing, handled specially in Typer and Unpickler.
- def AppliedTypeTree(tpt: Tree, args: List[Tree])(implicit ctx: Context): AppliedTypeTree =
- untpd.AppliedTypeTree(tpt, args).withType(tpt.tpe.appliedTo(args map (_.tpe))).checked
+ def AppliedTypeTree(tycon: Tree, args: List[Tree])(implicit ctx: Context): AppliedTypeTree =
+ ta.assignType(untpd.AppliedTypeTree(tycon, args), tycon, args)
def ByNameTypeTree(result: Tree)(implicit ctx: Context): ByNameTypeTree =
- untpd.ByNameTypeTree(result).withType(ExprType(result.tpe)).checked
+ ta.assignType(untpd.ByNameTypeTree(result), result)
def TypeBoundsTree(lo: Tree, hi: Tree)(implicit ctx: Context): TypeBoundsTree =
- untpd.TypeBoundsTree(lo, hi).withType(TypeBounds(lo.tpe, hi.tpe)).checked
+ ta.assignType(untpd.TypeBoundsTree(lo, hi), lo, hi)
def Bind(sym: TermSymbol, body: Tree)(implicit ctx: Context): Bind =
- untpd.Bind(sym.name, body).withType(sym.termRef).checked
+ ta.assignType(untpd.Bind(sym.name, body), sym)
def Alternative(trees: List[Tree])(implicit ctx: Context): Alternative =
- untpd.Alternative(trees).withType(ctx.typeComparer.lub(trees map (_.tpe))).checked
+ ta.assignType(untpd.Alternative(trees), trees)
- def UnApply(fun: Tree, implicits: List[Tree], patterns: List[Tree])(implicit ctx: Context): UnApply = {
- val owntype = fun.tpe.widen match {
- case MethodType(_, paramType :: Nil) => paramType
- case _ => check(false); ErrorType
- }
- untpd.UnApply(fun, implicits, patterns).withType(owntype).checked
- }
+ def UnApply(fun: Tree, implicits: List[Tree], patterns: List[Tree], proto: Type)(implicit ctx: Context): UnApply =
+ ta.assignType(untpd.UnApply(fun, implicits, patterns), proto)
def ValDef(sym: TermSymbol, rhs: Tree = EmptyTree)(implicit ctx: Context): ValDef =
- untpd.ValDef(Modifiers(sym), sym.name, TypeTree(sym.info), rhs).withType(sym.valRef).checked
+ ta.assignType(untpd.ValDef(Modifiers(sym), sym.name, TypeTree(sym.info), rhs), sym)
def DefDef(sym: TermSymbol, rhs: Tree = EmptyTree)(implicit ctx: Context): DefDef =
- DefDef(sym, Function.const(rhs) _)
+ ta.assignType(DefDef(sym, Function.const(rhs) _), sym)
def DefDef(sym: TermSymbol, rhsFn: List[List[Tree]] => Tree)(implicit ctx: Context): DefDef = {
-
val (tparams, mtp) = sym.info match {
case tp: PolyType =>
val tparams = ctx.newTypeParams(sym, tp.paramNames, EmptyFlags, tp.instantiateBounds)
@@ -269,15 +187,14 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
}
val (vparamss, rtp) = valueParamss(mtp)
val argss = vparamss map (_ map (vparam => Ident(vparam.termRef)))
- untpd.DefDef(
- Modifiers(sym), sym.name, tparams map TypeDef,
- vparamss map (_ map (ValDef(_))), TypeTree(rtp), rhsFn(argss))
- .withType(sym.termRefWithSig).checked
+ ta.assignType(
+ untpd.DefDef(
+ Modifiers(sym), sym.name, tparams map TypeDef,
+ vparamss map (_ map (ValDef(_))), TypeTree(rtp), rhsFn(argss)), sym)
}
def TypeDef(sym: TypeSymbol)(implicit ctx: Context): TypeDef =
- untpd.TypeDef(Modifiers(sym), sym.name, TypeTree(sym.info))
- .withType(sym.typeRef).checked
+ ta.assignType(untpd.TypeDef(Modifiers(sym), sym.name, TypeTree(sym.info)), sym)
def ClassDef(cls: ClassSymbol, constr: DefDef, body: List[Tree])(implicit ctx: Context): TypeDef = {
val parents = cls.info.parents map (TypeTree(_))
@@ -295,18 +212,17 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
.orElse(ctx.newLocalDummy(cls))
val impl = untpd.Template(constr, parents, selfType, newTypeParams ++ body)
.withType(localDummy.termRef).checked
- untpd.TypeDef(Modifiers(cls), cls.name, impl)
- .withType(cls.typeRef).checked
+ ta.assignType(untpd.TypeDef(Modifiers(cls), cls.name, impl), cls)
}
def Import(expr: Tree, selectors: List[untpd.Tree])(implicit ctx: Context): Import =
- untpd.Import(expr, selectors).withType(ctx.newImportSymbol(expr).termRef).checked
+ ta.assignType(untpd.Import(expr, selectors), ctx.newImportSymbol(expr))
def PackageDef(pid: RefTree, stats: List[Tree])(implicit ctx: Context): PackageDef =
- untpd.PackageDef(pid, stats).withType(pid.symbol.namedType).checked
+ ta.assignType(untpd.PackageDef(pid, stats), pid)
def Annotated(annot: Tree, arg: Tree)(implicit ctx: Context): Annotated =
- untpd.Annotated(annot, arg).withType(AnnotatedType(Annotation(annot), arg.tpe)).checked
+ ta.assignType(untpd.Annotated(annot, arg), annot, arg)
// ------ Making references ------------------------------------------------------
@@ -321,14 +237,6 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
def ref(sym: Symbol)(implicit ctx: Context): tpd.NameTree =
ref(NamedType(sym.owner.thisType, sym.name, sym.denot))
- // ----- Converting to releated trees -----------------------------------------------
-
- def underlyingIfRepeated(id: Ident)(implicit ctx: Context): Ident =
- if (id.isType) id else id withType id.tpe.underlyingIfRepeated
-
- def seqToRepeated(tree: Tree)(implicit ctx: Context): Tree =
- Typed(tree, TypeTree(tree.tpe.widen.translateParameterized(defn.SeqClass, defn.RepeatedParamClass)))
-
// ------ Creating typed equivalents of trees that exist only in untyped form -------
/** new C(args) */
@@ -451,7 +359,7 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
}
}
override def transformStats(trees: List[tpd.Tree])(implicit ctx: Context) = {
- val locals = localSyms(trees)
+ val locals = ta.localSyms(trees)
val mapped = ctx.mapSymbols(locals, typeMap, ownerMap)
if (locals eq mapped) super.transform(trees)
else withSubstitution(locals, mapped).transform(trees)
@@ -474,7 +382,5 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
// ensure that constructors are fully applied?
// ensure that normal methods are fully applied?
- def localSyms(stats: List[tpd.Tree])(implicit ctx: Context): List[Symbol] =
- for (stat <- stats if stat.isDef) yield stat.symbol
}
diff --git a/src/dotty/tools/dotc/core/Contexts.scala b/src/dotty/tools/dotc/core/Contexts.scala
index dd96023d7..9be2e2f43 100644
--- a/src/dotty/tools/dotc/core/Contexts.scala
+++ b/src/dotty/tools/dotc/core/Contexts.scala
@@ -119,10 +119,11 @@ object Contexts {
protected def scope_=(scope: Scope) = _scope = scope
def scope: Scope = _scope
- /** The current typer */
- private[this] var _typer: Typer = _
- protected def typer_=(typer: Typer) = _typer = typer
- def typer: Typer = _typer
+ /** The current type assigner ot typer */
+ private[this] var _typeAssigner: TypeAssigner = _
+ protected def typeAssigner_=(typeAssigner: TypeAssigner) = _typeAssigner = typeAssigner
+ def typeAssigner: TypeAssigner = _typeAssigner
+ def typer: Typer = _typeAssigner.asInstanceOf[Typer]
/** The currently active import info */
private[this] var _importInfo: ImportInfo = _
@@ -312,7 +313,8 @@ object Contexts {
def withTree(tree: Tree[_ >: Untyped]): this.type = { this.tree = tree; this }
def withScope(scope: Scope): this.type = { this.scope = scope; this }
def withNewScope: this.type = { this.scope = newScope; this }
- def withTyper(typer: Typer): this.type = { this.typer = typer; this.scope = typer.scope; this }
+ def withTypeAssigner(typeAssigner: TypeAssigner): this.type = { this.typeAssigner = typeAssigner; this }
+ def withTyper(typer: Typer): this.type = { this.scope = typer.scope; withTypeAssigner(typer) }
def withImportInfo(importInfo: ImportInfo): this.type = { this.importInfo = importInfo; this }
def withRunInfo(runInfo: RunInfo): this.type = { this.runInfo = runInfo; this }
def withDiagnostics(diagnostics: Option[StringBuilder]): this.type = { this.diagnostics = diagnostics; this }
@@ -342,6 +344,7 @@ object Contexts {
owner = NoSymbol
sstate = settings.defaultState
tree = untpd.EmptyTree
+ typeAssigner = TypeAssigner
runInfo = new RunInfo(this)
diagnostics = None
moreProperties = Map.empty
diff --git a/src/dotty/tools/dotc/core/TypeComparer.scala b/src/dotty/tools/dotc/core/TypeComparer.scala
index d46a8387f..da8263ac1 100644
--- a/src/dotty/tools/dotc/core/TypeComparer.scala
+++ b/src/dotty/tools/dotc/core/TypeComparer.scala
@@ -715,10 +715,28 @@ class TypeComparer(initctx: Context) extends DotClass {
/** Two types are the same if are mutual subtypes of each other */
def isSameType(tp1: Type, tp2: Type): Boolean =
- if (tp1 == NoType || tp2 == NoType) false
+ if (tp1 eq NoType) false
else if (tp1 eq tp2) true
else isSubType(tp1, tp2) && isSubType(tp2, tp1)
+ /** Same as `isSameType` but also can be applied to overloaded TermRefs, where
+ * two overloaded refs are the same if they have pairwise equal alternatives
+ */
+ def isSameRef(tp1: Type, tp2: Type): Boolean = ctx.traceIndented(s"isSameRef($tp1, $tp2") {
+ def isSubRef(tp1: Type, tp2: Type): Boolean = tp1 match {
+ case tp1: TermRef if tp1.isOverloaded =>
+ tp1.alternatives forall (isSubRef(_, tp2))
+ case _ =>
+ tp2 match {
+ case tp2: TermRef if tp2.isOverloaded =>
+ tp2.alternatives exists (isSubRef(tp1, _))
+ case _ =>
+ isSubType(tp1, tp2)
+ }
+ }
+ isSubRef(tp1, tp2) && isSubRef(tp2, tp1)
+ }
+
/** The greatest lower bound of two types */
def glb(tp1: Type, tp2: Type): Type = /*>|>*/ ctx.traceIndented(s"glb(${tp1.show}, ${tp2.show})", typr, show = true) /*<|<*/ {
if (tp1 eq tp2) tp1
diff --git a/src/dotty/tools/dotc/core/Types.scala b/src/dotty/tools/dotc/core/Types.scala
index f9c8aad5c..bb30d9a9c 100644
--- a/src/dotty/tools/dotc/core/Types.scala
+++ b/src/dotty/tools/dotc/core/Types.scala
@@ -1140,7 +1140,7 @@ object Types {
override def isOverloaded(implicit ctx: Context) = denot.isOverloaded
private def rewrap(sd: SingleDenotation)(implicit ctx: Context) =
- TermRef(prefix, name, sd)
+ TermRef.withSig(prefix, name, sd.signature, sd)
def alternatives(implicit ctx: Context): List[TermRef] =
denot.alternatives map rewrap
diff --git a/src/dotty/tools/dotc/core/pickling/UnPickler.scala b/src/dotty/tools/dotc/core/pickling/UnPickler.scala
index c69f60758..622752570 100644
--- a/src/dotty/tools/dotc/core/pickling/UnPickler.scala
+++ b/src/dotty/tools/dotc/core/pickling/UnPickler.scala
@@ -988,7 +988,7 @@ class UnPickler(bytes: Array[Byte], classRoot: ClassDenotation, moduleClassRoot:
case UNAPPLYtree =>
val fun = readTreeRef()
val args = until(end, readTreeRef)
- UnApply(fun, Nil, args) // !!! this is wrong in general
+ UnApply(fun, Nil, args, defn.AnyType) // !!! this is wrong in general
case ARRAYVALUEtree =>
val elemtpt = readTreeRef()
@@ -1067,7 +1067,7 @@ class UnPickler(bytes: Array[Byte], classRoot: ClassDenotation, moduleClassRoot:
setSym()
val qual = readTreeRef()
val mix = readTypeNameRef()
- Super(qual, mix)
+ Super(qual, mix, inConstrCall = false) // todo: revise
case THIStree =>
setSym()
diff --git a/src/dotty/tools/dotc/printing/RefinedPrinter.scala b/src/dotty/tools/dotc/printing/RefinedPrinter.scala
index 2702143c1..5231ccd93 100644
--- a/src/dotty/tools/dotc/printing/RefinedPrinter.scala
+++ b/src/dotty/tools/dotc/printing/RefinedPrinter.scala
@@ -7,7 +7,7 @@ import Contexts.Context, Scopes.Scope, Denotations.Denotation, Annotations.Annot
import StdNames.nme
import ast.{Trees, untpd}
import typer.Namer
-import typer.Inferencing.{SelectionProto, ViewProto}
+import typer.ProtoTypes.{SelectionProto, ViewProto, FunProto}
import Trees._
import scala.annotation.switch
@@ -120,7 +120,7 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) {
}
case ExprType(result) =>
return "=> " ~ toText(result)
- case typer.Inferencing.FunProto(args, resultType, _) =>
+ case FunProto(args, resultType, _) =>
return "funproto(" ~ toTextGlobal(args, ", ") ~ "):" ~ toText(resultType)
case _ =>
}
diff --git a/src/dotty/tools/dotc/typer/Applications.scala b/src/dotty/tools/dotc/typer/Applications.scala
index ce3198c64..cf0d7d0a1 100644
--- a/src/dotty/tools/dotc/typer/Applications.scala
+++ b/src/dotty/tools/dotc/typer/Applications.scala
@@ -19,7 +19,7 @@ import ErrorReporting._
import Trees._
import Names._
import StdNames._
-import Inferencing._
+import ProtoTypes._
import EtaExpansion._
import collection.mutable
import reflect.ClassTag
@@ -398,8 +398,9 @@ trait Applications extends Compatibility { self: Typer =>
val result = {
var typedArgs = typedArgBuf.toList
- val ownType =
- if (!success) ErrorType
+ val app0 = cpy.Apply(app, normalizedFun, typedArgs)
+ val app1 =
+ if (!success) app0.withType(ErrorType)
else {
if (!sameSeq(args, orderedArgs)) {
// need to lift arguments to maintain evaluation order in the
@@ -411,9 +412,9 @@ trait Applications extends Compatibility { self: Typer =>
}
if (sameSeq(typedArgs, args)) // trick to cut down on tree copying
typedArgs = args.asInstanceOf[List[Tree]]
- methodType.instantiate(typedArgs.tpes)
+ assignType(app0, normalizedFun, typedArgs)
}
- wrapDefs(liftedDefs, cpy.Apply(app, normalizedFun, typedArgs).withType(ownType))
+ wrapDefs(liftedDefs, app1)
}
}
@@ -513,21 +514,11 @@ trait Applications extends Compatibility { self: Typer =>
def typedTypeApply(tree: untpd.TypeApply, pt: Type)(implicit ctx: Context): Tree = track("typedTypeApply") {
val typedArgs = tree.args mapconserve (typedType(_))
val typedFn = typedExpr(tree.fun, PolyProto(typedArgs.tpes, pt))
- val ownType = typedFn.tpe.widen match {
- case pt: PolyType =>
- checkBounds(typedArgs, pt, tree.pos)
- val argTypes = typedArgs.tpes
- if (argTypes.length == pt.paramNames.length)
- pt.resultType.substParams(pt, typedArgs.tpes)
- else {
- ctx.error(i"wrong number of type parameters for ${typedFn.tpe}; expected: ${pt.paramNames.length}", tree.pos)
- ErrorType
- }
+ typedFn.tpe.widen match {
+ case pt: PolyType => checkBounds(typedArgs, pt, tree.pos)
case _ =>
- ctx.error(s"${err.exprStr(typedFn)} does not take type parameters", tree.pos)
- ErrorType
}
- cpy.TypeApply(tree, typedFn, typedArgs).withType(ownType)
+ assignType(cpy.TypeApply(tree, typedFn, typedArgs), typedFn, typedArgs)
}
def typedUnApply(tree: untpd.Apply, pt: Type)(implicit ctx: Context): Tree = track("typedUnApply") {
@@ -577,13 +568,13 @@ trait Applications extends Compatibility { self: Typer =>
/** Produce a typed qual.unappy or qual.unappySeq tree, or
* else if this fails follow a type alias and try again.
*/
- val unapply = trySelectUnapply(qual) { sel =>
+ val unapplyFn = trySelectUnapply(qual) { sel =>
val qual1 = followTypeAlias(qual)
if (qual1.isEmpty) notAnExtractor(sel)
else trySelectUnapply(qual1)(_ => notAnExtractor(sel))
}
- def fromScala2x = unapply.symbol.exists && (unapply.symbol.owner is Scala2x)
+ def fromScala2x = unapplyFn.symbol.exists && (unapplyFn.symbol.owner is Scala2x)
def unapplyArgs(unapplyResult: Type)(implicit ctx: Context): List[Type] = {
def extractorMemberType(tp: Type, name: Name) = {
@@ -609,7 +600,7 @@ trait Applications extends Compatibility { self: Typer =>
// println(s"unapply $unapplyResult ${extractorMemberType(unapplyResult, nme.isDefined)}")
if (extractorMemberType(unapplyResult, nme.isDefined) isRef defn.BooleanClass) {
if (getTp.exists)
- if (unapply.symbol.name == nme.unapplySeq) {
+ if (unapplyFn.symbol.name == nme.unapplySeq) {
val seqArg = boundsToHi(getTp.firstBaseArgInfo(defn.SeqClass))
if (seqArg.exists) return args map Function.const(seqArg)
}
@@ -634,7 +625,7 @@ trait Applications extends Compatibility { self: Typer =>
case _ => false
}
- unapply.tpe.widen match {
+ unapplyFn.tpe.widen match {
case mt: MethodType if mt.paramTypes.length == 1 && !mt.isDependent =>
val unapplyArgType = mt.paramTypes.head
unapp.println(s"unapp arg tpe = ${unapplyArgType.show}, pt = ${pt.show}")
@@ -661,7 +652,7 @@ trait Applications extends Compatibility { self: Typer =>
// can open unsoundness holes. See SI-7952 for an example of the hole this opens.
if (ctx.settings.verbose.value) ctx.warning(msg, tree.pos)
} else {
- unapp.println(s" ${unapply.symbol.owner} ${unapply.symbol.owner is Scala2x}")
+ unapp.println(s" ${unapplyFn.symbol.owner} ${unapplyFn.symbol.owner is Scala2x}")
ctx.error(msg, tree.pos)
}
case _ =>
@@ -677,7 +668,7 @@ trait Applications extends Compatibility { self: Typer =>
}
val dummyArg = dummyTreeOfType(unapplyArgType)
- val unapplyApp = typedExpr(untpd.TypedSplice(Apply(unapply, dummyArg :: Nil)))
+ val unapplyApp = typedExpr(untpd.TypedSplice(Apply(unapplyFn, dummyArg :: Nil)))
val unapplyImplicits = unapplyApp match {
case Apply(Apply(unapply, `dummyArg` :: Nil), args2) => assert(args2.nonEmpty); args2
case Apply(unapply, `dummyArg` :: Nil) => Nil
@@ -695,12 +686,12 @@ trait Applications extends Compatibility { self: Typer =>
List.fill(argTypes.length - args.length)(WildcardType)
}
val unapplyPatterns = (bunchedArgs, argTypes).zipped map (typed(_, _))
- val result = cpy.UnApply(tree, unapply, unapplyImplicits, unapplyPatterns) withType ownType
+ val result = assignType(cpy.UnApply(tree, unapplyFn, unapplyImplicits, unapplyPatterns), ownType)
unapp.println(s"unapply patterns = $unapplyPatterns")
if ((ownType eq pt) || ownType.isError) result
else Typed(result, TypeTree(ownType))
case tp =>
- val unapplyErr = if (tp.isError) unapply else notAnExtractor(unapply)
+ val unapplyErr = if (tp.isError) unapplyFn else notAnExtractor(unapplyFn)
val typedArgsErr = args mapconserve (typed(_, defn.AnyType))
cpy.UnApply(tree, unapplyErr, Nil, typedArgsErr) withType ErrorType
}
diff --git a/src/dotty/tools/dotc/typer/Checking.scala b/src/dotty/tools/dotc/typer/Checking.scala
new file mode 100644
index 000000000..25e6a7aa7
--- /dev/null
+++ b/src/dotty/tools/dotc/typer/Checking.scala
@@ -0,0 +1,141 @@
+package dotty.tools
+package dotc
+package typer
+
+import core._
+import ast._
+import Contexts._, Types._, Flags._, Denotations._, Names._, StdNames._, NameOps._, Symbols._
+import Trees._, ProtoTypes._
+import Constants._
+import Scopes._
+import annotation.unchecked
+import util.Positions._
+import util.{Stats, SimpleMap}
+import util.common._
+import Decorators._
+import Uniques._
+import ErrorReporting.{errorType, InfoString}
+import config.Printers._
+import collection.mutable
+
+trait NoChecking {
+ import tpd._
+ def checkValue(tree: Tree, proto: Type)(implicit ctx: Context): tree.type = tree
+ def checkBounds(args: List[tpd.Tree], poly: PolyType, pos: Position)(implicit ctx: Context): Unit = ()
+ def checkStable(tp: Type, pos: Position)(implicit ctx: Context): Unit = ()
+ def checkClassTypeWithStablePrefix(tp: Type, pos: Position, traitReq: Boolean)(implicit ctx: Context): Type = tp
+ def checkImplicitTptNonEmpty(defTree: untpd.ValOrDefDef)(implicit ctx: Context): Unit = ()
+ def checkImplicitParamsNotSingletons(vparamss: List[List[ValDef]])(implicit ctx: Context): Unit = ()
+ def checkFeasible(tp: Type, pos: Position, where: => String = "")(implicit ctx: Context): Type = tp
+ def checkNoDoubleDefs(cls: Symbol)(implicit ctx: Context): Unit = ()
+}
+
+trait Checking extends NoChecking {
+
+ import tpd._
+
+ /** Check that Java statics and packages can only be used in selections.
+ */
+ override def checkValue(tree: Tree, proto: Type)(implicit ctx: Context): tree.type = {
+ if (!proto.isInstanceOf[SelectionProto]) {
+ val sym = tree.tpe.termSymbol
+ if ((sym is Package) || (sym is JavaModule)) ctx.error(i"$sym is not a value", tree.pos)
+ }
+ tree
+ }
+
+ /** Check that type arguments `args` conform to corresponding bounds in `poly` */
+ override def checkBounds(args: List[tpd.Tree], poly: PolyType, pos: Position)(implicit ctx: Context): Unit =
+ for ((arg, bounds) <- args zip poly.paramBounds) {
+ def notConforms(which: String, bound: Type) =
+ ctx.error(i"Type argument ${arg.tpe} does not conform to $which bound $bound", arg.pos)
+ if (!(arg.tpe <:< bounds.hi)) notConforms("upper", bounds.hi)
+ if (!(bounds.lo <:< arg.tpe)) notConforms("lower", bounds.lo)
+ }
+
+ /** Check that type `tp` is stable.
+ * @return The type itself
+ */
+ override def checkStable(tp: Type, pos: Position)(implicit ctx: Context): Unit =
+ if (!tp.isStable) ctx.error(i"Prefix of type ${tp.widenIfUnstable} is not stable", pos)
+
+ /** Check that `tp` is a class type with a stable prefix. Also, if `isFirst` is
+ * false check that `tp` is a trait.
+ * @return `tp` itself if it is a class or trait ref, ObjectClass.typeRef if not.
+ */
+ override def checkClassTypeWithStablePrefix(tp: Type, pos: Position, traitReq: Boolean)(implicit ctx: Context): Type =
+ tp.underlyingClassRef match {
+ case tref: TypeRef =>
+ checkStable(tref.prefix, pos)
+ if (traitReq && !(tref.symbol is Trait)) ctx.error(i"$tref is not a trait", pos)
+ tp
+ case _ =>
+ ctx.error(i"$tp is not a class type", pos)
+ defn.ObjectClass.typeRef
+ }
+
+ /** Check that (return) type of implicit definition is not empty */
+ override def checkImplicitTptNonEmpty(defTree: untpd.ValOrDefDef)(implicit ctx: Context): Unit = defTree.tpt match {
+ case TypeTree(original) if original.isEmpty =>
+ val resStr = if (defTree.isInstanceOf[untpd.DefDef]) "result " else ""
+ ctx.error(i"${resStr}type of implicit definition needs to be given explicitly", defTree.pos)
+ case _ =>
+ }
+
+ /** Check that a non-implicit parameter making up the first parameter section of an
+ * implicit conversion is not a singleton type.
+ */
+ override def checkImplicitParamsNotSingletons(vparamss: List[List[ValDef]])(implicit ctx: Context): Unit = vparamss match {
+ case (vparam :: Nil) :: _ if !(vparam.symbol is Implicit) =>
+ if (vparam.tpt.tpe.isInstanceOf[SingletonType])
+ ctx.error(s"implicit conversion may not have a parameter of singleton type", vparam.tpt.pos)
+ case _ =>
+ }
+
+ /** Check that any top-level type arguments in this type are feasible, i.e. that
+ * their lower bound conforms to their upper cound. If a type argument is
+ * infeasible, issue and error and continue with upper bound.
+ */
+ override def checkFeasible(tp: Type, pos: Position, where: => String = "")(implicit ctx: Context): Type = tp match {
+ case tp: RefinedType =>
+ tp.derivedRefinedType(tp.parent, tp.refinedName, checkFeasible(tp.refinedInfo, pos, where))
+ case tp @ TypeBounds(lo, hi) if !(lo <:< hi) =>
+ ctx.error(i"no type exists between low bound $lo and high bound $hi$where", pos)
+ tp.derivedTypeAlias(hi)
+ case _ =>
+ tp
+ }
+
+ /** Check that class does not define */
+ override def checkNoDoubleDefs(cls: Symbol)(implicit ctx: Context): Unit = {
+ val seen = new mutable.HashMap[Name, List[Symbol]] {
+ override def default(key: Name) = Nil
+ }
+ typr.println(i"check no double defs $cls")
+ for (decl <- cls.info.decls) {
+ for (other <- seen(decl.name)) {
+ typr.println(i"conflict? $decl $other")
+ if (decl.signature matches other.signature) {
+ def doubleDefError(decl: Symbol, other: Symbol): Unit = {
+ def ofType = if (decl.isType) "" else i": ${other.info}"
+ def explanation =
+ if (!decl.isSourceMethod) ""
+ else "\n (both definitions have the same erased type signature)"
+ ctx.error(i"$decl is already defined as $other$ofType$explanation", decl.pos)
+ }
+ if (decl is Synthetic) doubleDefError(other, decl)
+ else doubleDefError(decl, other)
+ }
+ if ((decl is HasDefaultParams) && (other is HasDefaultParams)) {
+ ctx.error(i"two or more overloaded variants of $decl have default arguments")
+ decl resetFlag HasDefaultParams
+ }
+ }
+ seen(decl.name) = decl :: seen(decl.name)
+ }
+ }
+
+ def checkInstantiatable(cls: ClassSymbol, pos: Position): Unit = {
+ ??? // to be done in later phase: check that class `cls` is legal in a new.
+ }
+} \ No newline at end of file
diff --git a/src/dotty/tools/dotc/typer/ErrorReporting.scala b/src/dotty/tools/dotc/typer/ErrorReporting.scala
index 032190625..397285f6a 100644
--- a/src/dotty/tools/dotc/typer/ErrorReporting.scala
+++ b/src/dotty/tools/dotc/typer/ErrorReporting.scala
@@ -5,7 +5,7 @@ package typer
import ast._
import core._
import Trees._
-import Types._, Inferencing._, Contexts._, Decorators._, Denotations._, Symbols._
+import Types._, ProtoTypes._, Contexts._, Decorators._, Denotations._, Symbols._
import Applications._, Implicits._
import util.Positions._
import printing.Showable
diff --git a/src/dotty/tools/dotc/typer/Implicits.scala b/src/dotty/tools/dotc/typer/Implicits.scala
index 008fe8966..b939c1b0d 100644
--- a/src/dotty/tools/dotc/typer/Implicits.scala
+++ b/src/dotty/tools/dotc/typer/Implicits.scala
@@ -20,8 +20,8 @@ import Decorators._
import Names._
import StdNames._
import Constants._
-import Inferencing._
import Applications._
+import ProtoTypes._
import ErrorReporting._
import Hashable._
import config.Config
diff --git a/src/dotty/tools/dotc/typer/Inferencing.scala b/src/dotty/tools/dotc/typer/Inferencing.scala
index ea3109afa..6d9afecab 100644
--- a/src/dotty/tools/dotc/typer/Inferencing.scala
+++ b/src/dotty/tools/dotc/typer/Inferencing.scala
@@ -8,6 +8,7 @@ import Contexts._, Types._, Flags._, Denotations._, Names._, StdNames._, NameOps
import Trees._
import Constants._
import Scopes._
+import ProtoTypes._
import annotation.unchecked
import util.Positions._
import util.{Stats, SimpleMap}
@@ -18,291 +19,10 @@ import ErrorReporting.{errorType, InfoString}
import config.Printers._
import collection.mutable
-object Inferencing {
+trait Inferencing { this: Checking =>
import tpd._
- /** A trait defining an `isCompatible` method. */
- trait Compatibility {
-
- /** Is there an implicit conversion from `tp` to `pt`? */
- def viewExists(tp: Type, pt: Type)(implicit ctx: Context): Boolean
-
- /** A type `tp` is compatible with a type `pt` if one of the following holds:
- * 1. `tp` is a subtype of `pt`
- * 2. `pt` is by name parameter type, and `tp` is compatible with its underlying type
- * 3. there is an implicit conversion from `tp` to `pt`.
- */
- def isCompatible(tp: Type, pt: Type)(implicit ctx: Context): Boolean =
- tp.widenExpr <:< pt.widenExpr || viewExists(tp, pt)
-
- /** Test compatibility after normalization in a fresh typerstate. */
- def normalizedCompatible(tp: Type, pt: Type)(implicit ctx: Context) = {
- val nestedCtx = ctx.fresh.withExploreTyperState
- isCompatible(normalize(tp, pt)(nestedCtx), pt)(nestedCtx)
- }
-
- /** Check that the result type of the current method
- * fits the given expected result type.
- */
- def constrainResult(mt: Type, pt: Type)(implicit ctx: Context): Boolean = pt match {
- case FunProto(_, result, _) =>
- mt match {
- case mt: MethodType =>
- mt.isDependent || constrainResult(mt.resultType, pt.resultType)
- case _ =>
- true
- }
- case _: ValueTypeOrProto if !(pt isRef defn.UnitClass) =>
- mt match {
- case mt: MethodType =>
- mt.isDependent || isCompatible(normalize(mt, pt), pt)
- case _ =>
- isCompatible(mt, pt)
- }
- case _ =>
- true
- }
- }
-
- object NoViewsAllowed extends Compatibility {
- override def viewExists(tp: Type, pt: Type)(implicit ctx: Context): Boolean = false
- }
-
- /** A prototype for expressions [] that are part of a selection operation:
- *
- * [ ].name: proto
- */
- abstract case class SelectionProto(val name: Name, val memberProto: Type, val compat: Compatibility)
- extends CachedProxyType with ProtoType with ValueTypeOrProto {
-
- override def isMatchedBy(tp1: Type)(implicit ctx: Context) = {
- name == nme.WILDCARD || {
- val mbr = tp1.member(name)
- def qualifies(m: SingleDenotation) = compat.normalizedCompatible(m.info, memberProto)
- mbr match { // hasAltWith inlined for performance
- case mbr: SingleDenotation => mbr.exists && qualifies(mbr)
- case _ => mbr hasAltWith qualifies
- }
- }
- }
-
- def underlying(implicit ctx: Context) = WildcardType
-
- def derivedSelectionProto(name: Name, memberProto: Type, compat: Compatibility)(implicit ctx: Context) =
- if ((name eq this.name) && (memberProto eq this.memberProto) && (compat eq this.compat)) this
- else SelectionProto(name, memberProto, compat)
-
- override def equals(that: Any): Boolean = that match {
- case that: SelectionProto =>
- (name eq that.name) && (memberProto == that.memberProto) && (compat eq that.compat)
- case _ =>
- false
- }
-
- def map(tm: TypeMap)(implicit ctx: Context) = derivedSelectionProto(name, tm(memberProto), compat)
- def fold[T](x: T, ta: TypeAccumulator[T])(implicit ctx: Context) = ta(x, memberProto)
-
- override def computeHash = addDelta(doHash(name, memberProto), if (compat == NoViewsAllowed) 1 else 0)
- }
-
- class CachedSelectionProto(name: Name, memberProto: Type, compat: Compatibility) extends SelectionProto(name, memberProto, compat)
-
- object SelectionProto {
- def apply(name: Name, memberProto: Type, compat: Compatibility)(implicit ctx: Context): SelectionProto = {
- val selproto = new CachedSelectionProto(name, memberProto, compat)
- if (compat eq NoViewsAllowed) unique(selproto) else selproto
- }
- }
-
- /** Create a selection proto-type, but only one level deep;
- * treat constructors specially
- */
- def selectionProto(name: Name, tp: Type, typer: Typer)(implicit ctx: Context) =
- if (name.isConstructorName) WildcardType
- else tp match {
- case tp: UnapplyFunProto => new UnapplySelectionProto(name)
- case tp: ProtoType => SelectionProto(name, WildcardType, typer)
- case _ => SelectionProto(name, tp, typer)
- }
-
- /** A prototype for expressions [] that are in some unspecified selection operation
- *
- * [].?: ?
- *
- * Used to indicate that expression is in a context where the only valid
- * operation is further selection. In this case, the expression need not be a value.
- * @see checkValue
- */
- object AnySelectionProto extends SelectionProto(nme.WILDCARD, WildcardType, NoViewsAllowed)
-
- /** A prototype for selections in pattern constructors */
- class UnapplySelectionProto(name: Name) extends SelectionProto(name, WildcardType, NoViewsAllowed)
-
- trait ApplyingProto extends ProtoType
-
- /** A prototype for expressions that appear in function position
- *
- * [](args): resultType
- */
- case class FunProto(args: List[untpd.Tree], override val resultType: Type, typer: Typer)(implicit ctx: Context)
- extends UncachedGroundType with ApplyingProto {
- private var myTypedArgs: List[Tree] = Nil
-
- /** A map in which typed arguments can be stored to be later integrated in `typedArgs`. */
- private var myTypedArg: SimpleMap[untpd.Tree, Tree] = SimpleMap.Empty
-
- def isMatchedBy(tp: Type)(implicit ctx: Context) =
- typer.isApplicable(tp, Nil, typedArgs, resultType)
-
- def derivedFunProto(args: List[untpd.Tree], resultType: Type, typer: Typer) =
- if ((args eq this.args) && (resultType eq this.resultType) && (typer eq this.typer)) this
- else new FunProto(args, resultType, typer)
-
- def argsAreTyped: Boolean = myTypedArgs.nonEmpty || args.isEmpty
-
- /** The typed arguments. This takes any arguments already typed using
- * `typedArg` into account.
- */
- def typedArgs: List[Tree] = {
- if (!argsAreTyped)
- myTypedArgs = args mapconserve { arg =>
- val targ = myTypedArg(arg)
- if (targ != null) targ else typer.typed(arg)
- }
- myTypedArgs
- }
-
- /** Type single argument and remember the unadapted result in `myTypedArg`.
- * used to avoid repeated typings of trees when backtracking.
- */
- def typedArg(arg: untpd.Tree, formal: Type)(implicit ctx: Context): Tree = {
- var targ = myTypedArg(arg)
- if (targ == null) {
- val counts = ctx.reporter.errorCounts
- targ = typer.typedUnadapted(arg, formal)
- if (ctx.reporter.wasSilent(counts))
- myTypedArg = myTypedArg.updated(arg, targ)
- }
- typer.adapt(targ, formal)
- }
-
- override def toString = s"FunProto(${args mkString ","} => $resultType)"
-
- def map(tm: TypeMap)(implicit ctx: Context): FunProto =
- derivedFunProto(args, tm(resultType), typer)
-
- def fold[T](x: T, ta: TypeAccumulator[T])(implicit ctx: Context): T = ta(x, resultType)
- }
-
- /** A prototype for implicitly inferred views:
- *
- * []: argType => resultType
- */
- abstract case class ViewProto(argType: Type, override val resultType: Type)(implicit ctx: Context)
- extends CachedGroundType with ApplyingProto {
- def isMatchedBy(tp: Type)(implicit ctx: Context): Boolean = /*ctx.conditionalTraceIndented(lookingForInfo, i"?.info isMatchedBy $tp ${tp.getClass}")*/ {
- ctx.typer.isApplicable(tp, argType :: Nil, resultType)
- }
-
- def derivedViewProto(argType: Type, resultType: Type)(implicit ctx: Context) =
- if ((argType eq this.argType) && (resultType eq this.resultType)) this
- else ViewProto(argType, resultType)
-
- def map(tm: TypeMap)(implicit ctx: Context): ViewProto = derivedViewProto(tm(argType), tm(resultType))
-
- def fold[T](x: T, ta: TypeAccumulator[T])(implicit ctx: Context): T = ta(ta(x, argType), resultType)
-
- override def namedPartsWith(p: NamedType => Boolean)(implicit ctx: Context): collection.Set[NamedType] =
- AndType.unchecked(argType, resultType).namedPartsWith(p) // this is more efficient than oring two namedParts sets
- }
-
- class CachedViewProto(argType: Type, resultType: Type)(implicit ctx: Context) extends ViewProto(argType, resultType) {
- override def computeHash = doHash(argType, resultType)
- }
-
- object ViewProto {
- def apply(argType: Type, resultType: Type)(implicit ctx: Context) =
- unique(new CachedViewProto(argType, resultType))
- }
-
- class UnapplyFunProto(typer: Typer)(implicit ctx: Context) extends FunProto(
- untpd.TypedSplice(dummyTreeOfType(WildcardType)) :: Nil, WildcardType, typer)
-
- /** A prototype for expressions [] that are type-parameterized:
- *
- * [] [targs] resultType
- */
- case class PolyProto(targs: List[Type], override val resultType: Type) extends UncachedGroundType with ProtoType {
- override def isMatchedBy(tp: Type)(implicit ctx: Context) = {
- def isInstantiatable(tp: Type) = tp.widen match {
- case PolyType(paramNames) => paramNames.length == targs.length
- case _ => false
- }
- isInstantiatable(tp) || tp.member(nme.apply).hasAltWith(d => isInstantiatable(d.info))
- }
-
- def derivedPolyProto(targs: List[Type], resultType: Type) =
- if ((targs eq this.targs) && (resultType eq this.resultType)) this
- else PolyProto(targs, resultType)
-
- def map(tm: TypeMap)(implicit ctx: Context): PolyProto =
- derivedPolyProto(targs mapConserve tm, tm(resultType))
-
- def fold[T](x: T, ta: TypeAccumulator[T])(implicit ctx: Context): T =
- ta(ta.foldOver(x, targs), resultType)
- }
-
- /** A prototype for expressions [] that are known to be functions:
- *
- * [] _
- */
- object AnyFunctionProto extends UncachedGroundType with ProtoType {
- def isMatchedBy(tp: Type)(implicit ctx: Context) = true
- def map(tm: TypeMap)(implicit ctx: Context) = this
- def fold[T](x: T, ta: TypeAccumulator[T])(implicit ctx: Context) = x
- }
-
- /** The normalized form of a type
- * - unwraps polymorphic types, tracking their parameters in the current constraint
- * - skips implicit parameters
- * - converts non-dependent method types to the corresponding function types
- * - dereferences parameterless method types
- * - dereferences nullary method types provided the corresponding function type
- * is not a subtype of the expected type.
- * Note: We need to take account of the possibility of inserting a () argument list in normalization. Otherwise, a type with a
- * def toString(): String
- * member would not count as a valid solution for ?{toString: String}. This would then lead to an implicit
- * insertion, with a nice explosion of inference search because of course every implicit result has some sort
- * of toString method. The problem is solved by dereferencing nullary method types if the corresponding
- * function type is not compatible with the prototype.
- */
- def normalize(tp: Type, pt: Type)(implicit ctx: Context): Type = Stats.track("normalize") {
- tp.widenSingleton match {
- case poly: PolyType => normalize(constrained(poly).resultType, pt)
- case mt: MethodType if !mt.isDependent /*&& !pt.isInstanceOf[ApplyingProto]*/ =>
- if (mt.isImplicit) mt.resultType
- else {
- val rt = normalize(mt.resultType, pt)
- if (pt.isInstanceOf[ApplyingProto])
- mt.derivedMethodType(mt.paramNames, mt.paramTypes, rt)
- else {
- val ft = defn.FunctionType(mt.paramTypes, rt)
- if (mt.paramTypes.nonEmpty || ft <:< pt) ft else rt
- }
- }
- case et: ExprType => et.resultType
- case _ => tp
- }
- }
-
- /** An enumeration controlling the degree of forcing in "is-dully-defined" checks. */
- object ForceDegree extends Enumeration {
- val none, // don't force type variables
- noBottom, // force type variables, fail if forced to Nothing or Null
- all = Value // force type variables, don't fail
- }
-
/** Is type fully defined, meaning the type does not contain wildcard types
* or uninstantiated type variables. As a side effect, this will minimize
* any uninstantiated type variables, according to the given force degree,
@@ -395,54 +115,6 @@ object Inferencing {
case _ => NoType
}
- /** Check that type arguments `args` conform to corresponding bounds in `poly` */
- def checkBounds(args: List[tpd.Tree], poly: PolyType, pos: Position)(implicit ctx: Context): Unit =
- for ((arg, bounds) <- args zip poly.paramBounds) {
- def notConforms(which: String, bound: Type) =
- ctx.error(i"Type argument ${arg.tpe} does not conform to $which bound $bound", arg.pos)
- if (!(arg.tpe <:< bounds.hi)) notConforms("upper", bounds.hi)
- if (!(bounds.lo <:< arg.tpe)) notConforms("lower", bounds.lo)
- }
-
- /** Check that type `tp` is stable.
- * @return The type itself
- */
- def checkStable(tp: Type, pos: Position)(implicit ctx: Context): Unit =
- if (!tp.isStable) ctx.error(i"Prefix of type ${tp.widenIfUnstable} is not stable", pos)
-
- /** Check that `tp` is a class type with a stable prefix. Also, if `isFirst` is
- * false check that `tp` is a trait.
- * @return `tp` itself if it is a class or trait ref, ObjectClass.typeRef if not.
- */
- def checkClassTypeWithStablePrefix(tp: Type, pos: Position, traitReq: Boolean)(implicit ctx: Context): Type =
- tp.underlyingClassRef match {
- case tref: TypeRef =>
- checkStable(tref.prefix, pos)
- if (traitReq && !(tref.symbol is Trait)) ctx.error(i"$tref is not a trait", pos)
- tp
- case _ =>
- ctx.error(i"$tp is not a class type", pos)
- defn.ObjectClass.typeRef
- }
-
- /** Check that (return) type of implicit definition is not empty */
- def checkImplicitTptNonEmpty(defTree: untpd.ValOrDefDef)(implicit ctx: Context): Unit = defTree.tpt match {
- case TypeTree(original) if original.isEmpty =>
- val resStr = if (defTree.isInstanceOf[untpd.DefDef]) "result " else ""
- ctx.error(i"${resStr}type of implicit definition needs to be given explicitly", defTree.pos)
- case _ =>
- }
-
- /** Check that a non-implicit parameter making up the first parameter section of an
- * implicit conversion is not a singleton type.
- */
- def checkImplicitParamsNotSingletons(vparamss: List[List[ValDef]])(implicit ctx: Context): Unit = vparamss match {
- case (vparam :: Nil) :: _ if !(vparam.symbol is Implicit) =>
- if (vparam.tpt.tpe.isInstanceOf[SingletonType])
- ctx.error(s"implicit conversion may not have a parameter of singleton type", vparam.tpt.pos)
- case _ =>
- }
-
/** Ensure that the first type in a list of parent types Ps points to a non-trait class.
* If that's not already the case, add one. The added class type CT is determined as follows.
* First, let C be the unique class such that
@@ -484,134 +156,6 @@ object Inferencing {
TypeTree(checkFeasible(first, pos, i"\n in inferred parent $first")).withPos(pos) :: parents
}
- /** Check that any top-level type arguments in this type are feasible, i.e. that
- * their lower bound conforms to their upper cound. If a type argument is
- * infeasible, issue and error and continue with upper bound.
- */
- def checkFeasible(tp: Type, pos: Position, where: => String = "")(implicit ctx: Context): Type = tp match {
- case tp: RefinedType =>
- tp.derivedRefinedType(tp.parent, tp.refinedName, checkFeasible(tp.refinedInfo, pos, where))
- case tp @ TypeBounds(lo, hi) if !(lo <:< hi) =>
- ctx.error(i"no type exists between low bound $lo and high bound $hi$where", pos)
- tp.derivedTypeAlias(hi)
- case _ =>
- tp
- }
-
- /** Check that class does not define */
- def checkNoDoubleDefs(cls: Symbol)(implicit ctx: Context): Unit = {
- val seen = new mutable.HashMap[Name, List[Symbol]] {
- override def default(key: Name) = Nil
- }
- typr.println(i"check no double defs $cls")
- for (decl <- cls.info.decls) {
- for (other <- seen(decl.name)) {
- typr.println(i"conflict? $decl $other")
- if (decl.signature matches other.signature) {
- def doubleDefError(decl: Symbol, other: Symbol): Unit = {
- def ofType = if (decl.isType) "" else i": ${other.info}"
- def explanation =
- if (!decl.isSourceMethod) ""
- else "\n (both definitions have the same erased type signature)"
- ctx.error(i"$decl is already defined as $other$ofType$explanation", decl.pos)
- }
- if (decl is Synthetic) doubleDefError(other, decl)
- else doubleDefError(decl, other)
- }
- if ((decl is HasDefaultParams) && (other is HasDefaultParams)) {
- ctx.error(i"two or more overloaded variants of $decl have default arguments")
- decl resetFlag HasDefaultParams
- }
- }
- seen(decl.name) = decl :: seen(decl.name)
- }
- }
-
- def checkInstantiatable(cls: ClassSymbol, pos: Position): Unit = {
- ??? // to be done in later phase: check that class `cls` is legal in a new.
- }
-
- /** Approximate occurrences of parameter types and uninstantiated typevars
- * by wildcard types.
- */
- final def wildApprox(tp: Type, theMap: WildApproxMap = null)(implicit ctx: Context): Type = tp match {
- case tp: NamedType => // default case, inlined for speed
- if (tp.symbol.isStatic) tp
- else tp.derivedSelect(wildApprox(tp.prefix, theMap))
- case tp: RefinedType => // default case, inlined for speed
- tp.derivedRefinedType(wildApprox(tp.parent, theMap), tp.refinedName, wildApprox(tp.refinedInfo, theMap))
- case tp: TypeBounds if tp.lo eq tp.hi => // default case, inlined for speed
- tp.derivedTypeAlias(wildApprox(tp.lo, theMap))
- case PolyParam(pt, pnum) =>
- WildcardType(wildApprox(pt.paramBounds(pnum)).bounds)
- case MethodParam(mt, pnum) =>
- WildcardType(TypeBounds.upper(wildApprox(mt.paramTypes(pnum))))
- case tp: TypeVar =>
- val inst = tp.instanceOpt
- if (inst.exists) wildApprox(inst)
- else ctx.typerState.constraint.at(tp.origin) match {
- case bounds: TypeBounds => wildApprox(WildcardType(bounds))
- case NoType => WildcardType
- }
- case tp: AndType =>
- val tp1a = wildApprox(tp.tp1)
- val tp2a = wildApprox(tp.tp2)
- def wildBounds(tp: Type) =
- if (tp.isInstanceOf[WildcardType]) tp.bounds else TypeBounds.upper(tp)
- if (tp1a.isInstanceOf[WildcardType] || tp2a.isInstanceOf[WildcardType])
- WildcardType(wildBounds(tp1a) & wildBounds(tp2a))
- else
- tp.derivedAndType(tp1a, tp2a)
- case tp: OrType =>
- val tp1a = wildApprox(tp.tp1)
- val tp2a = wildApprox(tp.tp2)
- if (tp1a.isInstanceOf[WildcardType] || tp2a.isInstanceOf[WildcardType])
- WildcardType(tp1a.bounds | tp2a.bounds)
- else
- tp.derivedOrType(tp1a, tp2a)
- case tp: SelectionProto =>
- tp.derivedSelectionProto(tp.name, wildApprox(tp.memberProto), NoViewsAllowed)
- case tp: ViewProto =>
- tp.derivedViewProto(wildApprox(tp.argType), wildApprox(tp.resultType))
- case _: ThisType | _: BoundType | NoPrefix => // default case, inlined for speed
- tp
- case _ =>
- (if (theMap != null) theMap else new WildApproxMap).mapOver(tp)
- }
-
- private[Inferencing] class WildApproxMap(implicit ctx: Context) extends TypeMap {
- def apply(tp: Type) = wildApprox(tp, this)
- }
-
- /** Add all parameters in given polytype `pt` to the constraint's domain.
- * If the constraint contains already some of these parameters in its domain,
- * make a copy of the polytype and add the copy's type parameters instead.
- * Return either the original polytype, or the copy, if one was made.
- * Also, if `owningTree` is non-empty, add a type variable for each parameter.
- * @return The added polytype, and the list of created type variables.
- */
- def constrained(pt: PolyType, owningTree: untpd.Tree)(implicit ctx: Context): (PolyType, List[TypeVar]) = {
- val state = ctx.typerState
- def howmany = if (owningTree.isEmpty) "no" else "some"
- def committable = if (ctx.typerState.isCommittable) "committable" else "uncommittable"
- assert(owningTree.isEmpty != ctx.typerState.isCommittable,
- s"inconsistent: $howmany typevars were added to $committable constraint ${state.constraint}")
-
- def newTypeVars(pt: PolyType): List[TypeVar] =
- for (n <- (0 until pt.paramNames.length).toList)
- yield new TypeVar(PolyParam(pt, n), state, owningTree)
-
- val added =
- if (state.constraint contains pt) pt.copy(pt.paramNames, pt.paramBounds, pt.resultType)
- else pt
- val tvars = if (owningTree.isEmpty) Nil else newTypeVars(added)
- state.constraint = state.constraint.add(added, tvars)
- (added, tvars)
- }
-
- /** Same as `constrained(pt, EmptyTree)`, but returns just the created polytype */
- def constrained(pt: PolyType)(implicit ctx: Context): PolyType = constrained(pt, EmptyTree)._1
-
/** Interpolate those undetermined type variables in the widened type of this tree
* which are introduced by type application contained in the tree.
* If such a variable appears covariantly in type `tp` or does not appear at all,
@@ -665,31 +209,12 @@ object Inferencing {
}
result
}
-
- private lazy val dummyTree = untpd.Literal(Constant(null))
-
- /** Dummy tree to be used as an argument of a FunProto or ViewProto type */
- def dummyTreeOfType(tp: Type): Tree = dummyTree withTypeUnchecked tp
}
-/* not needed right now
-
- def isSubTypes(actuals: List[Type], formals: List[Type])(implicit ctx: Context): Boolean = formals match {
- case formal :: formals1 =>
- actuals match {
- case actual :: actuals1 => actual <:< formal && isSubTypes(actuals1, formals1)
- case _ => false
- }
- case nil =>
- actuals.isEmpty
- }
+/** An enumeration controlling the degree of forcing in "is-dully-defined" checks. */
+object ForceDegree extends Enumeration {
+ val none, // don't force type variables
+ noBottom, // force type variables, fail if forced to Nothing or Null
+ all = Value // force type variables, don't fail
+}
- def formalParameters[T](mtp: MethodType, actuals: List[T])(isRepeated: T => Boolean)(implicit ctx: Context) =
- if (mtp.isVarArgs && !(actuals.nonEmpty && isRepeated(actuals.last))) {
- val leading = mtp.paramTypes.init
- val repeated = mtp.paramTypes.last.typeArgs.head
- val trailing = List.fill(actuals.length - leading.length)(repeated)
- leading ++ trailing
- }
- else mtp.paramTypes
- */ \ No newline at end of file
diff --git a/src/dotty/tools/dotc/typer/Namer.scala b/src/dotty/tools/dotc/typer/Namer.scala
index 463b7e71e..c24021936 100644
--- a/src/dotty/tools/dotc/typer/Namer.scala
+++ b/src/dotty/tools/dotc/typer/Namer.scala
@@ -7,7 +7,7 @@ import ast._
import Trees._, Constants._, StdNames._, Scopes._, Denotations._
import Contexts._, Symbols._, Types._, SymDenotations._, Names._, NameOps._, Flags._, Decorators._
import ast.desugar, ast.desugar._
-import Inferencing._
+import ProtoTypes._
import util.Positions._
import util.{Attachment, SourcePosition, DotClass}
import collection.mutable
@@ -58,14 +58,16 @@ trait NamerContextOps { this: Context =>
/** The symbol (stored in some typer's symTree) of an enclosing context definition */
def symOfContextTree(tree: untpd.Tree) = {
def go(ctx: Context): Symbol = {
- val typer = ctx.typer
- if (typer == null) NoSymbol
- else tree.getAttachment(typer.SymOfTree) match {
- case Some(sym) => sym
- case None =>
- var cx = ctx.outer
- while (cx.typer eq typer) cx = cx.outer
- go(cx)
+ ctx.typeAssigner match {
+ case typer: Typer =>
+ tree.getAttachment(typer.SymOfTree) match {
+ case Some(sym) => sym
+ case None =>
+ var cx = ctx.outer
+ while (cx.typeAssigner eq typer) cx = cx.outer
+ go(cx)
+ }
+ case _ => NoSymbol
}
}
go(this)
@@ -589,7 +591,7 @@ class Namer { typer: Typer =>
(paramSymss.isEmpty || paramSymss.head.nonEmpty && (paramSymss.head.head is Implicit)))
paramSymss = Nil :: paramSymss
val restpe1 = // try to make anonymous functions non-dependent, so that they can be used in closures
- if (name == nme.ANON_FUN) tpd.avoid(restpe, paramSymss.flatten)
+ if (name == nme.ANON_FUN) avoid(restpe, paramSymss.flatten)
else restpe
val monotpe =
(paramSymss :\ restpe1) { (params, restpe) =>
diff --git a/src/dotty/tools/dotc/typer/ProtoTypes.scala b/src/dotty/tools/dotc/typer/ProtoTypes.scala
new file mode 100644
index 000000000..b4068408b
--- /dev/null
+++ b/src/dotty/tools/dotc/typer/ProtoTypes.scala
@@ -0,0 +1,384 @@
+package dotty.tools
+package dotc
+package typer
+
+import core._
+import ast._
+import Contexts._, Types._, Flags._, Denotations._, Names._, StdNames._, NameOps._, Symbols._
+import Trees._
+import Constants._
+import Scopes._
+import annotation.unchecked
+import util.Positions._
+import util.{Stats, SimpleMap}
+import util.common._
+import Decorators._
+import Uniques._
+import ErrorReporting.{errorType, InfoString}
+import config.Printers._
+import collection.mutable
+
+object ProtoTypes {
+
+ import tpd._
+
+ /** A trait defining an `isCompatible` method. */
+ trait Compatibility {
+
+ /** Is there an implicit conversion from `tp` to `pt`? */
+ def viewExists(tp: Type, pt: Type)(implicit ctx: Context): Boolean
+
+ /** A type `tp` is compatible with a type `pt` if one of the following holds:
+ * 1. `tp` is a subtype of `pt`
+ * 2. `pt` is by name parameter type, and `tp` is compatible with its underlying type
+ * 3. there is an implicit conversion from `tp` to `pt`.
+ */
+ def isCompatible(tp: Type, pt: Type)(implicit ctx: Context): Boolean =
+ tp.widenExpr <:< pt.widenExpr || viewExists(tp, pt)
+
+ /** Test compatibility after normalization in a fresh typerstate. */
+ def normalizedCompatible(tp: Type, pt: Type)(implicit ctx: Context) = {
+ val nestedCtx = ctx.fresh.withExploreTyperState
+ isCompatible(normalize(tp, pt)(nestedCtx), pt)(nestedCtx)
+ }
+
+ /** Check that the result type of the current method
+ * fits the given expected result type.
+ */
+ def constrainResult(mt: Type, pt: Type)(implicit ctx: Context): Boolean = pt match {
+ case FunProto(_, result, _) =>
+ mt match {
+ case mt: MethodType =>
+ mt.isDependent || constrainResult(mt.resultType, pt.resultType)
+ case _ =>
+ true
+ }
+ case _: ValueTypeOrProto if !(pt isRef defn.UnitClass) =>
+ mt match {
+ case mt: MethodType =>
+ mt.isDependent || isCompatible(normalize(mt, pt), pt)
+ case _ =>
+ isCompatible(mt, pt)
+ }
+ case _ =>
+ true
+ }
+ }
+
+ object NoViewsAllowed extends Compatibility {
+ override def viewExists(tp: Type, pt: Type)(implicit ctx: Context): Boolean = false
+ }
+
+ /** A prototype for expressions [] that are part of a selection operation:
+ *
+ * [ ].name: proto
+ */
+ abstract case class SelectionProto(val name: Name, val memberProto: Type, val compat: Compatibility)
+ extends CachedProxyType with ProtoType with ValueTypeOrProto {
+
+ override def isMatchedBy(tp1: Type)(implicit ctx: Context) = {
+ name == nme.WILDCARD || {
+ val mbr = tp1.member(name)
+ def qualifies(m: SingleDenotation) = compat.normalizedCompatible(m.info, memberProto)
+ mbr match { // hasAltWith inlined for performance
+ case mbr: SingleDenotation => mbr.exists && qualifies(mbr)
+ case _ => mbr hasAltWith qualifies
+ }
+ }
+ }
+
+ def underlying(implicit ctx: Context) = WildcardType
+
+ def derivedSelectionProto(name: Name, memberProto: Type, compat: Compatibility)(implicit ctx: Context) =
+ if ((name eq this.name) && (memberProto eq this.memberProto) && (compat eq this.compat)) this
+ else SelectionProto(name, memberProto, compat)
+
+ override def equals(that: Any): Boolean = that match {
+ case that: SelectionProto =>
+ (name eq that.name) && (memberProto == that.memberProto) && (compat eq that.compat)
+ case _ =>
+ false
+ }
+
+ def map(tm: TypeMap)(implicit ctx: Context) = derivedSelectionProto(name, tm(memberProto), compat)
+ def fold[T](x: T, ta: TypeAccumulator[T])(implicit ctx: Context) = ta(x, memberProto)
+
+ override def computeHash = addDelta(doHash(name, memberProto), if (compat eq NoViewsAllowed) 1 else 0)
+ }
+
+ class CachedSelectionProto(name: Name, memberProto: Type, compat: Compatibility) extends SelectionProto(name, memberProto, compat)
+
+ object SelectionProto {
+ def apply(name: Name, memberProto: Type, compat: Compatibility)(implicit ctx: Context): SelectionProto = {
+ val selproto = new CachedSelectionProto(name, memberProto, compat)
+ if (compat eq NoViewsAllowed) unique(selproto) else selproto
+ }
+ }
+
+ /** Create a selection proto-type, but only one level deep;
+ * treat constructors specially
+ */
+ def selectionProto(name: Name, tp: Type, typer: Typer)(implicit ctx: Context) =
+ if (name.isConstructorName) WildcardType
+ else tp match {
+ case tp: UnapplyFunProto => new UnapplySelectionProto(name)
+ case tp: ProtoType => SelectionProto(name, WildcardType, typer)
+ case _ => SelectionProto(name, tp, typer)
+ }
+
+ /** A prototype for expressions [] that are in some unspecified selection operation
+ *
+ * [].?: ?
+ *
+ * Used to indicate that expression is in a context where the only valid
+ * operation is further selection. In this case, the expression need not be a value.
+ * @see checkValue
+ */
+ object AnySelectionProto extends SelectionProto(nme.WILDCARD, WildcardType, NoViewsAllowed)
+
+ /** A prototype for selections in pattern constructors */
+ class UnapplySelectionProto(name: Name) extends SelectionProto(name, WildcardType, NoViewsAllowed)
+
+ trait ApplyingProto extends ProtoType
+
+ /** A prototype for expressions that appear in function position
+ *
+ * [](args): resultType
+ */
+ case class FunProto(args: List[untpd.Tree], override val resultType: Type, typer: Typer)(implicit ctx: Context)
+ extends UncachedGroundType with ApplyingProto {
+ private var myTypedArgs: List[Tree] = Nil
+
+ /** A map in which typed arguments can be stored to be later integrated in `typedArgs`. */
+ private var myTypedArg: SimpleMap[untpd.Tree, Tree] = SimpleMap.Empty
+
+ def isMatchedBy(tp: Type)(implicit ctx: Context) =
+ typer.isApplicable(tp, Nil, typedArgs, resultType)
+
+ def derivedFunProto(args: List[untpd.Tree], resultType: Type, typer: Typer) =
+ if ((args eq this.args) && (resultType eq this.resultType) && (typer eq this.typer)) this
+ else new FunProto(args, resultType, typer)
+
+ def argsAreTyped: Boolean = myTypedArgs.nonEmpty || args.isEmpty
+
+ /** The typed arguments. This takes any arguments already typed using
+ * `typedArg` into account.
+ */
+ def typedArgs: List[Tree] = {
+ if (!argsAreTyped)
+ myTypedArgs = args mapconserve { arg =>
+ val targ = myTypedArg(arg)
+ if (targ != null) targ else typer.typed(arg)
+ }
+ myTypedArgs
+ }
+
+ /** Type single argument and remember the unadapted result in `myTypedArg`.
+ * used to avoid repeated typings of trees when backtracking.
+ */
+ def typedArg(arg: untpd.Tree, formal: Type)(implicit ctx: Context): Tree = {
+ var targ = myTypedArg(arg)
+ if (targ == null) {
+ val counts = ctx.reporter.errorCounts
+ targ = typer.typedUnadapted(arg, formal)
+ if (ctx.reporter.wasSilent(counts))
+ myTypedArg = myTypedArg.updated(arg, targ)
+ }
+ typer.adapt(targ, formal)
+ }
+
+ override def toString = s"FunProto(${args mkString ","} => $resultType)"
+
+ def map(tm: TypeMap)(implicit ctx: Context): FunProto =
+ derivedFunProto(args, tm(resultType), typer)
+
+ def fold[T](x: T, ta: TypeAccumulator[T])(implicit ctx: Context): T = ta(x, resultType)
+ }
+
+ /** A prototype for implicitly inferred views:
+ *
+ * []: argType => resultType
+ */
+ abstract case class ViewProto(argType: Type, override val resultType: Type)(implicit ctx: Context)
+ extends CachedGroundType with ApplyingProto {
+ def isMatchedBy(tp: Type)(implicit ctx: Context): Boolean = /*ctx.conditionalTraceIndented(lookingForInfo, i"?.info isMatchedBy $tp ${tp.getClass}")*/ {
+ ctx.typer.isApplicable(tp, argType :: Nil, resultType)
+ }
+
+ def derivedViewProto(argType: Type, resultType: Type)(implicit ctx: Context) =
+ if ((argType eq this.argType) && (resultType eq this.resultType)) this
+ else ViewProto(argType, resultType)
+
+ def map(tm: TypeMap)(implicit ctx: Context): ViewProto = derivedViewProto(tm(argType), tm(resultType))
+
+ def fold[T](x: T, ta: TypeAccumulator[T])(implicit ctx: Context): T = ta(ta(x, argType), resultType)
+
+ override def namedPartsWith(p: NamedType => Boolean)(implicit ctx: Context): collection.Set[NamedType] =
+ AndType.unchecked(argType, resultType).namedPartsWith(p) // this is more efficient than oring two namedParts sets
+ }
+
+ class CachedViewProto(argType: Type, resultType: Type)(implicit ctx: Context) extends ViewProto(argType, resultType) {
+ override def computeHash = doHash(argType, resultType)
+ }
+
+ object ViewProto {
+ def apply(argType: Type, resultType: Type)(implicit ctx: Context) =
+ unique(new CachedViewProto(argType, resultType))
+ }
+
+ class UnapplyFunProto(typer: Typer)(implicit ctx: Context) extends FunProto(
+ untpd.TypedSplice(dummyTreeOfType(WildcardType)) :: Nil, WildcardType, typer)
+
+ /** A prototype for expressions [] that are type-parameterized:
+ *
+ * [] [targs] resultType
+ */
+ case class PolyProto(targs: List[Type], override val resultType: Type) extends UncachedGroundType with ProtoType {
+ override def isMatchedBy(tp: Type)(implicit ctx: Context) = {
+ def isInstantiatable(tp: Type) = tp.widen match {
+ case PolyType(paramNames) => paramNames.length == targs.length
+ case _ => false
+ }
+ isInstantiatable(tp) || tp.member(nme.apply).hasAltWith(d => isInstantiatable(d.info))
+ }
+
+ def derivedPolyProto(targs: List[Type], resultType: Type) =
+ if ((targs eq this.targs) && (resultType eq this.resultType)) this
+ else PolyProto(targs, resultType)
+
+ def map(tm: TypeMap)(implicit ctx: Context): PolyProto =
+ derivedPolyProto(targs mapConserve tm, tm(resultType))
+
+ def fold[T](x: T, ta: TypeAccumulator[T])(implicit ctx: Context): T =
+ ta(ta.foldOver(x, targs), resultType)
+ }
+
+ /** A prototype for expressions [] that are known to be functions:
+ *
+ * [] _
+ */
+ object AnyFunctionProto extends UncachedGroundType with ProtoType {
+ def isMatchedBy(tp: Type)(implicit ctx: Context) = true
+ def map(tm: TypeMap)(implicit ctx: Context) = this
+ def fold[T](x: T, ta: TypeAccumulator[T])(implicit ctx: Context) = x
+ }
+
+ /** Add all parameters in given polytype `pt` to the constraint's domain.
+ * If the constraint contains already some of these parameters in its domain,
+ * make a copy of the polytype and add the copy's type parameters instead.
+ * Return either the original polytype, or the copy, if one was made.
+ * Also, if `owningTree` is non-empty, add a type variable for each parameter.
+ * @return The added polytype, and the list of created type variables.
+ */
+ def constrained(pt: PolyType, owningTree: untpd.Tree)(implicit ctx: Context): (PolyType, List[TypeVar]) = {
+ val state = ctx.typerState
+ def howmany = if (owningTree.isEmpty) "no" else "some"
+ def committable = if (ctx.typerState.isCommittable) "committable" else "uncommittable"
+ assert(owningTree.isEmpty != ctx.typerState.isCommittable,
+ s"inconsistent: $howmany typevars were added to $committable constraint ${state.constraint}")
+
+ def newTypeVars(pt: PolyType): List[TypeVar] =
+ for (n <- (0 until pt.paramNames.length).toList)
+ yield new TypeVar(PolyParam(pt, n), state, owningTree)
+
+ val added =
+ if (state.constraint contains pt) pt.copy(pt.paramNames, pt.paramBounds, pt.resultType)
+ else pt
+ val tvars = if (owningTree.isEmpty) Nil else newTypeVars(added)
+ state.constraint = state.constraint.add(added, tvars)
+ (added, tvars)
+ }
+
+ /** Same as `constrained(pt, EmptyTree)`, but returns just the created polytype */
+ def constrained(pt: PolyType)(implicit ctx: Context): PolyType = constrained(pt, EmptyTree)._1
+
+ /** The normalized form of a type
+ * - unwraps polymorphic types, tracking their parameters in the current constraint
+ * - skips implicit parameters
+ * - converts non-dependent method types to the corresponding function types
+ * - dereferences parameterless method types
+ * - dereferences nullary method types provided the corresponding function type
+ * is not a subtype of the expected type.
+ * Note: We need to take account of the possibility of inserting a () argument list in normalization. Otherwise, a type with a
+ * def toString(): String
+ * member would not count as a valid solution for ?{toString: String}. This would then lead to an implicit
+ * insertion, with a nice explosion of inference search because of course every implicit result has some sort
+ * of toString method. The problem is solved by dereferencing nullary method types if the corresponding
+ * function type is not compatible with the prototype.
+ */
+ def normalize(tp: Type, pt: Type)(implicit ctx: Context): Type = Stats.track("normalize") {
+ tp.widenSingleton match {
+ case poly: PolyType => normalize(constrained(poly).resultType, pt)
+ case mt: MethodType if !mt.isDependent /*&& !pt.isInstanceOf[ApplyingProto]*/ =>
+ if (mt.isImplicit) mt.resultType
+ else {
+ val rt = normalize(mt.resultType, pt)
+ if (pt.isInstanceOf[ApplyingProto])
+ mt.derivedMethodType(mt.paramNames, mt.paramTypes, rt)
+ else {
+ val ft = defn.FunctionType(mt.paramTypes, rt)
+ if (mt.paramTypes.nonEmpty || ft <:< pt) ft else rt
+ }
+ }
+ case et: ExprType => et.resultType
+ case _ => tp
+ }
+ }
+
+ /** Approximate occurrences of parameter types and uninstantiated typevars
+ * by wildcard types.
+ */
+ final def wildApprox(tp: Type, theMap: WildApproxMap = null)(implicit ctx: Context): Type = tp match {
+ case tp: NamedType => // default case, inlined for speed
+ if (tp.symbol.isStatic) tp
+ else tp.derivedSelect(wildApprox(tp.prefix, theMap))
+ case tp: RefinedType => // default case, inlined for speed
+ tp.derivedRefinedType(wildApprox(tp.parent, theMap), tp.refinedName, wildApprox(tp.refinedInfo, theMap))
+ case tp: TypeBounds if tp.lo eq tp.hi => // default case, inlined for speed
+ tp.derivedTypeAlias(wildApprox(tp.lo, theMap))
+ case PolyParam(pt, pnum) =>
+ WildcardType(wildApprox(pt.paramBounds(pnum)).bounds)
+ case MethodParam(mt, pnum) =>
+ WildcardType(TypeBounds.upper(wildApprox(mt.paramTypes(pnum))))
+ case tp: TypeVar =>
+ val inst = tp.instanceOpt
+ if (inst.exists) wildApprox(inst)
+ else ctx.typerState.constraint.at(tp.origin) match {
+ case bounds: TypeBounds => wildApprox(WildcardType(bounds))
+ case NoType => WildcardType
+ }
+ case tp: AndType =>
+ val tp1a = wildApprox(tp.tp1)
+ val tp2a = wildApprox(tp.tp2)
+ def wildBounds(tp: Type) =
+ if (tp.isInstanceOf[WildcardType]) tp.bounds else TypeBounds.upper(tp)
+ if (tp1a.isInstanceOf[WildcardType] || tp2a.isInstanceOf[WildcardType])
+ WildcardType(wildBounds(tp1a) & wildBounds(tp2a))
+ else
+ tp.derivedAndType(tp1a, tp2a)
+ case tp: OrType =>
+ val tp1a = wildApprox(tp.tp1)
+ val tp2a = wildApprox(tp.tp2)
+ if (tp1a.isInstanceOf[WildcardType] || tp2a.isInstanceOf[WildcardType])
+ WildcardType(tp1a.bounds | tp2a.bounds)
+ else
+ tp.derivedOrType(tp1a, tp2a)
+ case tp: SelectionProto =>
+ tp.derivedSelectionProto(tp.name, wildApprox(tp.memberProto), NoViewsAllowed)
+ case tp: ViewProto =>
+ tp.derivedViewProto(wildApprox(tp.argType), wildApprox(tp.resultType))
+ case _: ThisType | _: BoundType | NoPrefix => // default case, inlined for speed
+ tp
+ case _ =>
+ (if (theMap != null) theMap else new WildApproxMap).mapOver(tp)
+ }
+
+ private[ProtoTypes] class WildApproxMap(implicit ctx: Context) extends TypeMap {
+ def apply(tp: Type) = wildApprox(tp, this)
+ }
+
+ private lazy val dummyTree = untpd.Literal(Constant(null))
+
+ /** Dummy tree to be used as an argument of a FunProto or ViewProto type */
+ def dummyTreeOfType(tp: Type): Tree = dummyTree withTypeUnchecked tp
+} \ No newline at end of file
diff --git a/src/dotty/tools/dotc/typer/TypeAssigner.scala b/src/dotty/tools/dotc/typer/TypeAssigner.scala
new file mode 100644
index 000000000..6eeec56e1
--- /dev/null
+++ b/src/dotty/tools/dotc/typer/TypeAssigner.scala
@@ -0,0 +1,334 @@
+package dotty.tools
+package dotc
+package typer
+
+import core._
+import ast._
+import Scopes._, Contexts._, Constants._, Types._, Symbols._, Names._, Flags._, Decorators._
+import ErrorReporting._, Annotations._, Denotations._, SymDenotations._, StdNames._
+import util.Positions._
+import config.Printers._
+
+trait TypeAssigner {
+ import tpd._
+
+ /** The enclosing class, except if we are in a super call, in which case
+ * it is the next outer one.
+ */
+ def effectiveEnclosingClass(implicit ctx: Context) = {
+ val enclClass = ctx.owner.enclosingClass
+ if ((ctx.mode is Mode.InSuperCall) && enclClass.exists) enclClass.owner.enclosingClass
+ else enclClass
+ }
+
+ /** The qualifying class of a this or super with prefix `qual` (which might be empty).
+ * @param packageOk The qualifier may refer to a package.
+ */
+ def qualifyingClass(tree: untpd.Tree, qual: Name, packageOK: Boolean)(implicit ctx: Context): Symbol = {
+ effectiveEnclosingClass.ownersIterator.find(o => qual.isEmpty || o.isClass && o.name == qual) match {
+ case Some(c) if packageOK || !(c is Package) =>
+ c
+ case _ =>
+ ctx.error(
+ if (qual.isEmpty) tree.show + " can be used only in a class, object, or template"
+ else qual.show + " is not an enclosing class", tree.pos)
+ NoSymbol
+ }
+ }
+
+ def avoid(tp: Type, syms: => List[Symbol])(implicit ctx: Context): Type = {
+ val widenMap = new TypeMap {
+ lazy val forbidden = syms.toSet
+ def toAvoid(tp: Type): Boolean = tp match {
+ case tp: TermRef =>
+ val sym = tp.symbol
+ sym.exists && (
+ sym.owner.isTerm && (forbidden contains sym)
+ || !(sym.owner is Package) && toAvoid(tp.prefix)
+ )
+ case _ =>
+ false
+ }
+ def apply(tp: Type) = tp match {
+ case tp: TermRef if toAvoid(tp) && variance > 0 =>
+ apply(tp.info)
+ case tp: TypeRef if toAvoid(tp.prefix) =>
+ tp.info match {
+ case TypeAlias(ref) => apply(ref)
+ case _ => mapOver(tp)
+ }
+ case tp: RefinedType =>
+ val tp1 @ RefinedType(parent1, _) = mapOver(tp)
+ if (tp1.refinedInfo existsPart toAvoid) {
+ typr.println(s"dropping refinement from $tp1")
+ parent1
+ }
+ else tp1
+ case _ =>
+ mapOver(tp)
+ }
+ }
+ widenMap(tp)
+ }
+
+ def localSyms(stats: List[tpd.Tree])(implicit ctx: Context): List[Symbol] =
+ for (stat <- stats if stat.isDef) yield stat.symbol
+
+ def seqToRepeated(tree: Tree)(implicit ctx: Context): Tree =
+ Typed(tree, TypeTree(tree.tpe.widen.translateParameterized(defn.SeqClass, defn.RepeatedParamClass)))
+
+ /** A denotation exists really if it exists and does not point to a stale symbol. */
+ final def reallyExists(denot: Denotation)(implicit ctx: Context): Boolean = try
+ denot match {
+ case denot: SymDenotation =>
+ denot.exists && {
+ denot.ensureCompleted
+ !denot.isAbsent
+ }
+ case denot: SingleDenotation =>
+ val sym = denot.symbol
+ (sym eq NoSymbol) || reallyExists(sym.denot)
+ case _ =>
+ true
+ }
+ catch {
+ case ex: StaleSymbol => false
+ }
+
+ /** If `tpe` is a named type, check that its denotation is accessible in the
+ * current context. Return the type with those alternatives as denotations
+ * which are accessible.
+ */
+ def ensureAccessible(tpe: Type, superAccess: Boolean, pos: Position)(implicit ctx: Context): Type = {
+ def test(tpe: Type, firstTry: Boolean): Type = tpe match {
+ case tpe: NamedType =>
+ val pre = tpe.prefix
+ val name = tpe.name
+ val d = tpe.denot.accessibleFrom(pre, superAccess)
+ if (!d.exists) {
+ // it could be that we found an inaccessbile private member, but there is
+ // an inherited non-private member with the same name and signature.
+ val d2 = pre.nonPrivateMember(name)
+ if (reallyExists(d2) && firstTry) test(pre.select(name, d2), false)
+ else {
+ val alts = tpe.denot.alternatives.map(_.symbol).filter(_.exists)
+ val what = alts match {
+ case Nil =>
+ name.toString
+ case sym :: Nil =>
+ if (sym.owner == pre.typeSymbol) sym.show else sym.showLocated
+ case _ =>
+ i"none of the overloaded alternatives named $name"
+ }
+ val where = if (ctx.owner.exists) s" from ${ctx.owner.enclosingClass}" else ""
+ val whyNot = new StringBuffer
+ alts foreach (_.isAccessibleFrom(pre, superAccess, whyNot))
+ if (!tpe.isError)
+ ctx.error(i"$what cannot be accessed as a member of $pre$where.$whyNot", pos)
+ ErrorType
+ }
+ } else if (d.symbol is TypeParamAccessor) // always dereference type param accessors
+ ensureAccessible(d.info.bounds.hi, superAccess, pos)
+ else
+ tpe withDenot d
+ case _ =>
+ tpe
+ }
+ test(tpe, true)
+ }
+
+ /** The type of a selection with `name` of a tree with type `site`.
+ */
+ def selectionType(site: Type, name: Name, pos: Position)(implicit ctx: Context): Type = {
+ val mbr = site.member(name)
+ if (reallyExists(mbr)) site.select(name, mbr)
+ else {
+ if (!site.isErroneous) {
+ ctx.error(
+ if (name == nme.CONSTRUCTOR) i"$site does not have a constructor"
+ else i"$name is not a member of $site", pos)
+ }
+ ErrorType
+ }
+ }
+
+ /** The selection type, which is additionally checked for accessibility.
+ */
+ def accessibleSelectionType(tree: untpd.RefTree, qual1: Tree)(implicit ctx: Context): Type = {
+ val ownType = selectionType(qual1.tpe.widenIfUnstable, tree.name, tree.pos)
+ ensureAccessible(ownType, qual1.isInstanceOf[Super], tree.pos)
+ }
+
+ /** Type assignment method. Each method takes as parameters
+ * - an untpd.Tree to which it assigns a type,
+ * - typed child trees it needs to access to cpmpute that type,
+ * - any further information it needs to access to compute that type.
+ */
+
+ def assignType(tree: untpd.Ident, rawType: Type)(implicit ctx: Context) = {
+ tree.withType(if (tree.isType) rawType else rawType.underlyingIfRepeated)
+ }
+
+ def assignType(tree: untpd.Select, qual: Tree)(implicit ctx: Context) = {
+ tree.withType(accessibleSelectionType(tree, qual))
+ }
+
+ def assignType(tree: untpd.SelectFromTypeTree, qual: Tree)(implicit ctx: Context) = {
+ tree.withType(accessibleSelectionType(tree, qual))
+ }
+
+ def assignType(tree: untpd.New, tpt: Tree)(implicit ctx: Context) =
+ tree.withType(tpt.tpe)
+
+ def assignType(tree: untpd.Literal)(implicit ctx: Context) =
+ tree.withType {
+ tree.const.tag match {
+ case UnitTag => defn.UnitType
+ case NullTag => defn.NullType
+ case _ => ConstantType(tree.const)
+ }
+ }
+
+ def assignType(tree: untpd.This)(implicit ctx: Context) = {
+ val cls = qualifyingClass(tree, tree.qual, packageOK = false)
+ tree.withType(cls.thisType)
+ }
+
+ def assignType(tree: untpd.Super, qual: Tree, inConstrCall: Boolean)(implicit ctx: Context) = {
+ val mix = tree.mix
+ val cls = qual.tpe.widen.typeSymbol
+
+ def findMixinSuper(site: Type): Type = site.parents filter (_.name == mix) match {
+ case p :: Nil =>
+ p
+ case Nil =>
+ errorType(i"$mix does not name a parent class of $cls", tree.pos)
+ case p :: q :: _ =>
+ errorType(s"ambiguous parent class qualifier", tree.pos)
+ }
+ val owntype =
+ if (!mix.isEmpty) findMixinSuper(cls.info)
+ else if (inConstrCall) cls.info.firstParent
+ else cls.info.parents.reduceLeft((x: Type, y: Type) => AndType(x, y))
+ tree.withType(SuperType(cls.thisType, owntype))
+ }
+
+ def assignType(tree: untpd.Apply, fn: Tree, args: List[Tree])(implicit ctx: Context) = {
+ val ownType = fn.tpe.widen match {
+ case fntpe @ MethodType(_, ptypes) =>
+ if (sameLength(ptypes, args)) fntpe.instantiate(args.tpes)
+ else errorType(s"wrong number of type parameters for ${fn.tpe}; expected: ${ptypes.length}", tree.pos)
+ case t =>
+ errorType(s"${err.exprStr(fn)} does not take type parameters", tree.pos)
+ }
+ tree.withType(ownType)
+ }
+
+ def assignType(tree: untpd.TypeApply, fn: Tree, args: List[Tree])(implicit ctx: Context) = {
+ val ownType = fn.tpe.widen match {
+ case pt: PolyType =>
+ val argTypes = args.tpes
+ if (sameLength(argTypes, pt.paramNames)) pt.instantiate(args.tpes)
+ else errorType(i"wrong number of type parameters for ${fn.tpe}; expected: ${pt.paramNames.length}", tree.pos)
+ case _ =>
+ errorType(s"${err.exprStr(fn)} does not take type parameters", tree.pos)
+ }
+ tree.withType(ownType)
+ }
+
+ def assignType(tree: untpd.Pair, left: Tree, right: Tree)(implicit ctx: Context) =
+ tree.withType(defn.PairType.appliedTo(left.tpe :: right.tpe :: Nil))
+
+ def assignType(tree: untpd.Typed, tpt: Tree)(implicit ctx: Context) =
+ tree.withType(tpt.tpe)
+
+ def assignType(tree: untpd.NamedArg, arg: Tree)(implicit ctx: Context) =
+ tree.withType(arg.tpe)
+
+ def assignType(tree: untpd.Assign)(implicit ctx: Context) =
+ tree.withType(defn.UnitType)
+
+ def assignType(tree: untpd.Block, stats: List[Tree], expr: Tree)(implicit ctx: Context) =
+ tree.withType(avoid(expr.tpe, localSyms(stats)))
+
+ def assignType(tree: untpd.If, thenp: Tree, elsep: Tree)(implicit ctx: Context) =
+ tree.withType(thenp.tpe | elsep.tpe)
+
+ def assignType(tree: untpd.Closure, meth: Tree, target: Tree)(implicit ctx: Context) =
+ tree.withType(if (target.isEmpty) meth.tpe.widen.toFunctionType else target.tpe)
+
+ def assignType(tree: untpd.CaseDef, body: Tree)(implicit ctx: Context) =
+ tree.withType(body.tpe)
+
+ def assignType(tree: untpd.Match, cases: List[CaseDef])(implicit ctx: Context) =
+ tree.withType(ctx.typeComparer.lub(cases.tpes))
+
+ def assignType(tree: untpd.Return)(implicit ctx: Context) =
+ tree.withType(defn.NothingType)
+
+ def assignType(tree: untpd.Try, expr: Tree, handler: Tree)(implicit ctx: Context) = {
+ val handlerTypeArgs = handler.tpe.baseArgTypesHi(defn.FunctionClass(1))
+ tree.withType(if (handlerTypeArgs.nonEmpty) expr.tpe | handlerTypeArgs(1) else expr.tpe)
+ }
+
+ def assignType(tree: untpd.Throw)(implicit ctx: Context) =
+ tree.withType(defn.NothingType)
+
+ def assignType(tree: untpd.SeqLiteral, elems: List[Tree])(implicit ctx: Context) =
+ tree.withType(defn.SeqType.appliedTo(ctx.typeComparer.lub(elems.tpes)))
+
+ def assignType(tree: untpd.SingletonTypeTree, ref: Tree)(implicit ctx: Context) =
+ tree.withType(ref.tpe)
+
+ def assignType(tree: untpd.AndTypeTree, left: Tree, right: Tree)(implicit ctx: Context) =
+ tree.withType(left.tpe & right.tpe)
+
+ def assignType(tree: untpd.OrTypeTree, left: Tree, right: Tree)(implicit ctx: Context) =
+ tree.withType(left.tpe | right.tpe)
+
+ // RefinedTypeTree is missing, handled specially in Typer and Unpickler.
+
+ def assignType(tree: untpd.AppliedTypeTree, tycon: Tree, args: List[Tree])(implicit ctx: Context) = {
+ val tparams = tycon.tpe.typeParams
+ val ownType =
+ if (sameLength(tparams, args)) tycon.tpe.appliedTo(args.tpes)
+ else errorType(i"wrong number of type arguments for ${tycon.tpe}, should be ${tparams.length}", tree.pos)
+ tree.withType(ownType)
+ }
+
+ def assignType(tree: untpd.ByNameTypeTree, result: Tree)(implicit ctx: Context) =
+ tree.withType(ExprType(result.tpe))
+
+ def assignType(tree: untpd.TypeBoundsTree, lo: Tree, hi: Tree)(implicit ctx: Context) =
+ tree.withType(TypeBounds(lo.tpe, hi.tpe))
+
+ def assignType(tree: untpd.Bind, sym: TermSymbol)(implicit ctx: Context) =
+ tree.withType(TermRef(NoPrefix, sym))
+
+ def assignType(tree: untpd.Alternative, trees: List[Tree])(implicit ctx: Context) =
+ tree.withType(ctx.typeComparer.lub(trees.tpes))
+
+ def assignType(tree: untpd.UnApply, proto: Type)(implicit ctx: Context) =
+ tree.withType(proto)
+
+ def assignType(tree: untpd.ValDef, sym: Symbol)(implicit ctx: Context) =
+ tree.withType(if (sym.exists) sym.valRef else NoType)
+
+ def assignType(tree: untpd.DefDef, sym: Symbol)(implicit ctx: Context) =
+ tree.withType(sym.termRefWithSig)
+
+ def assignType(tree: untpd.TypeDef, sym: Symbol)(implicit ctx: Context) =
+ tree.withType(sym.typeRef)
+
+ def assignType(tree: untpd.Import, sym: Symbol)(implicit ctx: Context) =
+ tree.withType(sym.termRef)
+
+ def assignType(tree: untpd.Annotated, annot: Tree, arg: Tree)(implicit ctx: Context) =
+ tree.withType(AnnotatedType(Annotation(annot), arg.tpe))
+
+ def assignType(tree: untpd.PackageDef, pid: Tree)(implicit ctx: Context) =
+ tree.withType(pid.symbol.valRef)
+}
+
+object TypeAssigner extends TypeAssigner
+
diff --git a/src/dotty/tools/dotc/typer/Typer.scala b/src/dotty/tools/dotc/typer/Typer.scala
index 6cc3a226e..51eba3b02 100644
--- a/src/dotty/tools/dotc/typer/Typer.scala
+++ b/src/dotty/tools/dotc/typer/Typer.scala
@@ -9,7 +9,7 @@ import Constants._
import StdNames._
import Scopes._
import Denotations._
-import Inferencing._
+import ProtoTypes._
import Contexts._
import Symbols._
import Types._
@@ -20,7 +20,6 @@ import NameOps._
import Flags._
import Decorators._
import ErrorReporting._
-import Inferencing.{FunProto, PolyProto, Compatibility, normalize}
import EtaExpansion.etaExpand
import util.Positions._
import util.common._
@@ -49,7 +48,7 @@ object Typer {
}
}
-class Typer extends Namer with Applications with Implicits {
+class Typer extends Namer with TypeAssigner with Applications with Implicits with Inferencing with Checking {
import Typer._
import tpd.{cpy => _, _}
@@ -63,122 +62,6 @@ class Typer extends Namer with Applications with Implicits {
*/
private var importedFromRoot: Set[Symbol] = Set()
- /** A denotation exists really if it exists and does not point to a stale symbol. */
- final def reallyExists(denot: Denotation)(implicit ctx: Context): Boolean = try
- denot match {
- case denot: SymDenotation =>
- denot.exists && {
- denot.ensureCompleted
- !denot.isAbsent
- }
- case denot: SingleDenotation =>
- val sym = denot.symbol
- (sym eq NoSymbol) || reallyExists(sym.denot)
- case _ =>
- true
- }
- catch {
- case ex: StaleSymbol => false
- }
-
- /** The type of a selection with `name` of a tree with type `site`.
- */
- def selectionType(site: Type, name: Name, pos: Position)(implicit ctx: Context): Type = {
- val mbr = site.member(name)
- if (reallyExists(mbr)) site.select(name, mbr)
- else {
- if (!site.isErroneous) {
- typr.println(s"site = $site, baseClasses = ${site.baseClasses}")
- ctx.error(
- if (name == nme.CONSTRUCTOR) i"$site does not have a constructor"
- else i"$name is not a member of $site", pos)
- }
- ErrorType
- }
- }
-
- /** The selection type, which is additionally checked for accessibility.
- */
- def checkedSelectionType(qual1: Tree, tree: untpd.RefTree)(implicit ctx: Context): Type = {
- val ownType = selectionType(qual1.tpe.widenIfUnstable, tree.name, tree.pos)
- checkAccessible(ownType, qual1.isInstanceOf[Super], tree.pos)
- }
-
- /** Check that Java statics and packages can only be used in selections.
- */
- def checkValue(tpe: Type, proto: Type, pos: Position)(implicit ctx: Context): Unit =
- if (!proto.isInstanceOf[SelectionProto]) {
- val sym = tpe.termSymbol
- if ((sym is Package) || (sym is JavaModule)) ctx.error(i"$sym is not a value", pos)
- }
-
- /** If `tpe` is a named type, check that its denotation is accessible in the
- * current context. Return the type with those alternatives as denotations
- * which are accessible.
- */
- def checkAccessible(tpe: Type, superAccess: Boolean, pos: Position)(implicit ctx: Context): Type = {
- def test(tpe: Type, firstTry: Boolean): Type = tpe match {
- case tpe: NamedType =>
- val pre = tpe.prefix
- val name = tpe.name
- val d = tpe.denot.accessibleFrom(pre, superAccess)
- if (!d.exists) {
- // it could be that we found an inaccessbile private member, but there is
- // an inherited non-private member with the same name and signature.
- val d2 = pre.nonPrivateMember(name)
- if (reallyExists(d2) && firstTry) test(pre.select(name, d2), false)
- else {
- val alts = tpe.denot.alternatives.map(_.symbol).filter(_.exists)
- val what = alts match {
- case Nil =>
- name.toString
- case sym :: Nil =>
- if (sym.owner == pre.typeSymbol) sym.show else sym.showLocated
- case _ =>
- i"none of the overloaded alternatives named $name"
- }
- val where = if (ctx.owner.exists) s" from ${ctx.owner.enclosingClass}" else ""
- val whyNot = new StringBuffer
- val addendum =
- alts foreach (_.isAccessibleFrom(pre, superAccess, whyNot))
- if (!tpe.isError)
- ctx.error(i"$what cannot be accessed as a member of $pre$where.$whyNot", pos)
- ErrorType
- }
- } else if (d.symbol is TypeParamAccessor) // always dereference type param accessors
- checkAccessible(d.info.bounds.hi, superAccess, pos)
- else
- tpe withDenot d
- case _ =>
- tpe
- }
- test(tpe, true)
- }
-
- /** The enclosing class, except if we are in a super call, in which case
- * it is the next outer one.
- */
- def effectiveEnclosingClass(implicit ctx: Context) = {
- val enclClass = ctx.owner.enclosingClass
- if ((ctx.mode is Mode.InSuperCall) && enclClass.exists) enclClass.owner.enclosingClass
- else enclClass
- }
-
- /** The qualifying class of a this or super with prefix `qual` (which might be empty).
- * @param packageOk The qualifier may refer to a package.
- */
- def qualifyingClass(tree: untpd.Tree, qual: Name, packageOK: Boolean)(implicit ctx: Context): Symbol = {
- effectiveEnclosingClass.ownersIterator.find(o => qual.isEmpty || o.isClass && o.name == qual) match {
- case Some(c) if packageOK || !(c is Package) =>
- c
- case _ =>
- ctx.error(
- if (qual.isEmpty) tree.show + " can be used only in a class, object, or template"
- else qual.show + " is not an enclosing class", tree.pos)
- NoSymbol
- }
- }
-
/** Attribute an identifier consisting of a simple name or wildcard
*
* @param tree The tree representing the identifier.
@@ -245,7 +128,7 @@ class Typer extends Namer with Applications with Implicits {
* does properly shadow the new one from an outer context.
*/
def checkNewOrShadowed(found: Type, newPrec: Int): Type =
- if (!previous.exists || (previous =:= found)) found
+ if (!previous.exists || ctx.typeComparer.isSameRef(previous, found)) found
else if ((prevCtx.scope eq ctx.scope) &&
(newPrec == definition ||
newPrec == namedImport && prevPrec == wildImport)) {
@@ -369,60 +252,42 @@ class Typer extends Namer with Applications with Implicits {
val rawType =
try findRef(NoType, BindingPrec.nothingBound, NoContext)
finally importedFromRoot = saved
- checkValue(rawType, pt, tree.pos)
val ownType =
if (rawType.exists)
- checkAccessible(rawType, superAccess = false, tree.pos)
+ ensureAccessible(rawType, superAccess = false, tree.pos)
else {
error(i"not found: $kind$name", tree.pos)
ErrorType
}
- tree.withType(ownType.underlyingIfRepeated)
+ checkValue(tree.withType(ownType.underlyingIfRepeated), pt)
}
def typedSelect(tree: untpd.Select, pt: Type)(implicit ctx: Context): Tree = track("typedSelect") {
val qual1 = typedExpr(tree.qualifier, selectionProto(tree.name, pt, this))
- val ownType = checkedSelectionType(qual1, tree)
- checkValue(ownType, pt, tree.pos)
- cpy.Select(tree, qual1, tree.name).withType(ownType)
+ checkValue(assignType(cpy.Select(tree, qual1, tree.name), qual1), pt)
+ }
+
+ def typedSelectFromTypeTree(tree: untpd.SelectFromTypeTree, pt: Type)(implicit ctx: Context): SelectFromTypeTree = track("typedSelectFromTypeTree") {
+ val qual1 = typedType(tree.qualifier, selectionProto(tree.name, pt, this))
+ assignType(cpy.SelectFromTypeTree(tree, qual1, tree.name), qual1)
}
def typedThis(tree: untpd.This)(implicit ctx: Context): Tree = track("typedThis") {
- val cls = qualifyingClass(tree, tree.qual, packageOK = false)
- tree.withType(cls.thisType)
+ assignType(tree)
}
def typedSuper(tree: untpd.Super, pt: Type)(implicit ctx: Context): Tree = track("typedSuper") {
- val mix = tree.mix
val qual1 = typed(tree.qual)
- val cls = qual1.tpe.widen.typeSymbol
-
- def findMixinSuper(site: Type): Type = site.parents filter (_.name == mix) match {
- case p :: Nil =>
- p
- case Nil =>
- errorType(i"$mix does not name a parent class of $cls", tree.pos)
- case p :: q :: _ =>
- errorType(s"ambiguous parent class qualifier", tree.pos)
+ val inConstrCall = pt match {
+ case pt: SelectionProto if pt.name == nme.CONSTRUCTOR => true
+ case _ => false
}
- val owntype =
- if (!mix.isEmpty) findMixinSuper(cls.info)
- else pt match {
- case pt: SelectionProto if pt.name == nme.CONSTRUCTOR => cls.info.firstParent
- case _ => cls.info.parents.reduceLeft((x: Type, y: Type) => AndType(x, y))
- }
- cpy.Super(tree, qual1, mix).withType(SuperType(cls.thisType, owntype))
+ assignType(cpy.Super(tree, qual1, tree.mix), qual1, inConstrCall)
}
def typedLiteral(tree: untpd.Literal)(implicit ctx: Context) = track("typedLiteral") {
- tree.withType {
- tree.const.tag match {
- case UnitTag => defn.UnitType
- case NullTag => defn.NullType
- case _ => ConstantType(tree.const)
- }
- }
+ assignType(tree)
}
def typedNew(tree: untpd.New, pt: Type)(implicit ctx: Context) = track("typedNew") {
@@ -433,10 +298,10 @@ class Typer extends Namer with Applications with Implicits {
val clsDef = TypeDef(Modifiers(Final), x, templ)
typed(cpy.Block(tree, clsDef :: Nil, New(Ident(x), Nil)), pt)
case _ =>
- val tpt1 = typedType(tree.tpt)
- val clsref = checkClassTypeWithStablePrefix(tpt1.tpe, tpt1.pos, traitReq = false)
+ val tpt1 = typedType(tree.tpt)
+ checkClassTypeWithStablePrefix(tpt1.tpe, tpt1.pos, traitReq = false)
+ assignType(cpy.New(tree, tpt1), tpt1)
// todo in a later phase: checkInstantiatable(cls, tpt1.pos)
- cpy.New(tree, tpt1).withType(tpt1.tpe)
}
}
@@ -447,7 +312,7 @@ class Typer extends Namer with Applications with Implicits {
}
val left1 = typed(tree.left, leftProto)
val right1 = typed(tree.right, rightProto)
- cpy.Pair(tree, left1, right1).withType(defn.PairType.appliedTo(left1.tpe :: right1.tpe :: Nil))
+ assignType(cpy.Pair(tree, left1, right1), left1, right1)
}
def typedTyped(tree: untpd.Typed, pt: Type)(implicit ctx: Context): Tree = track("typedTyped") {
@@ -456,7 +321,7 @@ class Typer extends Namer with Applications with Implicits {
val expr1 =
if (isWildcard) tree.expr withType tpt1.tpe
else typedExpr(tree.expr, tpt1.tpe)
- cpy.Typed(tree, expr1, tpt1).withType(tpt1.tpe)
+ assignType(cpy.Typed(tree, expr1, tpt1), tpt1)
}
tree.expr match {
case id: untpd.Ident if (ctx.mode is Mode.Pattern) && isVarPattern(id) =>
@@ -475,7 +340,7 @@ class Typer extends Namer with Applications with Implicits {
def typedNamedArg(tree: untpd.NamedArg, pt: Type)(implicit ctx: Context) = track("typedNamedArg") {
val arg1 = typed(tree.arg, pt)
- cpy.NamedArg(tree, tree.name, arg1).withType(arg1.tpe)
+ assignType(cpy.NamedArg(tree, tree.name, arg1), arg1)
}
def typedAssign(tree: untpd.Assign, pt: Type)(implicit ctx: Context) = track("typedAssign") {
@@ -491,7 +356,7 @@ class Typer extends Namer with Applications with Implicits {
def lhs1 = typed(untpd.TypedSplice(lhsCore))
lhsCore.tpe match {
case ref: TermRef if ref.symbol is (Mutable, butNot = Accessor) =>
- cpy.Assign(tree, lhs1, typed(tree.rhs, ref.info)).withType(defn.UnitType)
+ assignType(cpy.Assign(tree, lhs1, typed(tree.rhs, ref.info)))
case _ =>
def reassignmentToVal =
errorTree(cpy.Assign(tree, lhsCore, typed(tree.rhs, lhs1.tpe.widen)),
@@ -504,7 +369,7 @@ class Typer extends Namer with Applications with Implicits {
lhsCore match {
case lhsCore: RefTree if setter.exists =>
val setterTypeRaw = pre select (setterName, setter)
- val setterType = checkAccessible(setterTypeRaw, isSuperSelection(lhsCore), tree.pos)
+ val setterType = ensureAccessible(setterTypeRaw, isSuperSelection(lhsCore), tree.pos)
val lhs2 = lhsCore.withName(setterName).withType(setterType)
typed(cpy.Apply(tree, untpd.TypedSplice(lhs2), tree.rhs :: Nil))
case _ =>
@@ -521,8 +386,7 @@ class Typer extends Namer with Applications with Implicits {
val exprCtx = index(tree.stats)
val stats1 = typedStats(tree.stats, ctx.owner)
val expr1 = typedExpr(tree.expr, pt)(exprCtx)
- val result = cpy.Block(tree, stats1, expr1).withType(avoid(expr1.tpe, localSyms(stats1)))
- checkNoLocalRefs(result, pt)
+ ensureNoLocalRefs(assignType(cpy.Block(tree, stats1, expr1), stats1, expr1), pt)
}
/** Check that block's type can be expressed without references to locally defined
@@ -532,17 +396,18 @@ class Typer extends Namer with Applications with Implicits {
* 2. If (1) fails, force all type variables so that the block's type is
* fully defined and try again.
*/
- def checkNoLocalRefs(block: Block, pt: Type, forcedDefined: Boolean = false)(implicit ctx: Context): Tree = {
+ private def ensureNoLocalRefs(block: Block, pt: Type, forcedDefined: Boolean = false)(implicit ctx: Context): Tree = {
val Block(stats, expr) = block
val leaks = CheckTrees.escapingRefs(block)
if (leaks.isEmpty) block
else if (isFullyDefined(pt, ForceDegree.all)) {
- val expr1 = typed(untpd.Typed(untpd.TypedSplice(expr), untpd.TypeTree(pt)))
- untpd.Block(stats, expr1) withType expr1.tpe
+ val expr1 = Typed(expr, TypeTree(pt))
+ cpy.Block(block, stats, expr1) withType expr1.tpe // no assignType here because avoid is redundant
} else if (!forcedDefined) {
fullyDefinedType(block.tpe, "block", block.pos)
- val block1 = block.withType(avoid(block.tpe, localSyms(stats)))
- checkNoLocalRefs(block1, pt, forcedDefined = true)
+ val expr1 = Typed(expr, TypeTree(avoid(block.tpe, localSyms(stats))))
+ val block1 = cpy.Block(block, stats, expr1) withType expr1.tpe // no assignType here because avoid is already done
+ ensureNoLocalRefs(block1, pt, forcedDefined = true)
} else
errorTree(block,
i"local definition of ${leaks.head.name} escapes as part of block's type ${block.tpe}"/*; full type: ${result.tpe.toString}"*/)
@@ -552,7 +417,7 @@ class Typer extends Namer with Applications with Implicits {
val cond1 = typed(tree.cond, defn.BooleanType)
val thenp1 = typed(tree.thenp, pt)
val elsep1 = typed(tree.elsep orElse untpd.unitLiteral withPos tree.pos, pt)
- cpy.If(tree, cond1, thenp1, elsep1).withType(thenp1.tpe | elsep1.tpe)
+ assignType(cpy.If(tree, cond1, thenp1, elsep1), thenp1, elsep1)
}
def typedFunction(tree: untpd.Function, pt: Type)(implicit ctx: Context) = track("typedFunction") {
@@ -659,21 +524,21 @@ class Typer extends Namer with Applications with Implicits {
def typedClosure(tree: untpd.Closure, pt: Type)(implicit ctx: Context) = track("typedClosure") {
val env1 = tree.env mapconserve (typed(_))
val meth1 = typedUnadapted(tree.meth)
- val (ownType, target) = meth1.tpe.widen match {
+ val target = meth1.tpe.widen match {
case mt: MethodType =>
pt match {
case SAMType(meth) if !defn.isFunctionType(pt) && mt <:< meth.info =>
if (!isFullyDefined(pt, ForceDegree.all))
ctx.error(i"result type of closure is an underspecified SAM type $pt", tree.pos)
- (pt, TypeTree(pt))
+ TypeTree(pt)
case _ =>
- if (!mt.isDependent) (mt.toFunctionType, EmptyTree)
+ if (!mt.isDependent) EmptyTree
else throw new Error(i"internal error: cannot turn dependent method type $mt into closure, position = ${tree.pos}, raw type = ${mt.toString}") // !!! DEBUG. Eventually, convert to an error?
}
case tp =>
throw new Error(i"internal error: closing over non-method $tp, pos = ${tree.pos}")
}
- cpy.Closure(tree, env1, meth1, target).withType(ownType)
+ assignType(cpy.Closure(tree, env1, meth1, target), meth1, target)
}
def typedMatch(tree: untpd.Match, pt: Type)(implicit ctx: Context) = track("typedMatch") {
@@ -716,7 +581,7 @@ class Typer extends Namer with Applications with Implicits {
}
val guard1 = typedExpr(tree.guard, defn.BooleanType)
val body1 = typedExpr(tree.body, pt)
- cpy.CaseDef(tree, pat, guard1, body1) withType body1.tpe
+ assignType(cpy.CaseDef(tree, pat, guard1, body1), body1)
}
val doCase: () => CaseDef =
() => caseRest(typedPattern(tree.pat, selType))(ctx.fresh.withNewScope)
@@ -724,7 +589,7 @@ class Typer extends Namer with Applications with Implicits {
}
val cases1 = tree.cases mapconserve typedCase
- cpy.Match(tree, sel1, cases1).withType(ctx.typeComparer.lub(cases1.tpes))
+ assignType(cpy.Match(tree, sel1, cases1), cases1)
}
}
@@ -746,27 +611,25 @@ class Typer extends Namer with Applications with Implicits {
}
val (from, proto) = enclMethInfo(ctx)
val expr1 = typedExpr(tree.expr orElse untpd.unitLiteral.withPos(tree.pos), proto)
- cpy.Return(tree, expr1, from) withType defn.NothingType
+ assignType(cpy.Return(tree, expr1, from))
}
def typedTry(tree: untpd.Try, pt: Type)(implicit ctx: Context): Try = track("typedTry") {
val expr1 = typed(tree.expr, pt)
val handler1 = typed(tree.handler, defn.FunctionType(defn.ThrowableType :: Nil, pt))
val finalizer1 = typed(tree.finalizer, defn.UnitType)
- val handlerTypeArgs = handler1.tpe.baseArgTypesHi(defn.FunctionClass(1))
- val ownType = if (handlerTypeArgs.nonEmpty) expr1.tpe | handlerTypeArgs(1) else expr1.tpe
- cpy.Try(tree, expr1, handler1, finalizer1) withType ownType
+ assignType(cpy.Try(tree, expr1, handler1, finalizer1), expr1, handler1)
}
def typedThrow(tree: untpd.Throw)(implicit ctx: Context): Throw = track("typedThrow") {
val expr1 = typed(tree.expr, defn.ThrowableType)
- cpy.Throw(tree, expr1) withType defn.NothingType
+ assignType(cpy.Throw(tree, expr1))
}
def typedSeqLiteral(tree: untpd.SeqLiteral, pt: Type)(implicit ctx: Context): SeqLiteral = track("typedSeqLiteral") {
val proto1 = pt.elemType orElse WildcardType
val elems1 = tree.elems mapconserve (typed(_, proto1))
- cpy.SeqLiteral(tree, elems1) withType defn.SeqType.appliedTo(ctx.typeComparer.lub(elems1.tpes))
+ assignType(cpy.SeqLiteral(tree, elems1), elems1)
}
def typedTypeTree(tree: untpd.TypeTree, pt: Type)(implicit ctx: Context): TypeTree = track("typedTypeTree") {
@@ -780,24 +643,19 @@ class Typer extends Namer with Applications with Implicits {
def typedSingletonTypeTree(tree: untpd.SingletonTypeTree)(implicit ctx: Context): SingletonTypeTree = track("typedSingletonTypeTree") {
val ref1 = typedExpr(tree.ref)
checkStable(ref1.tpe, tree.pos)
- cpy.SingletonTypeTree(tree, ref1) withType ref1.tpe
- }
-
- def typedSelectFromTypeTree(tree: untpd.SelectFromTypeTree, pt: Type)(implicit ctx: Context): SelectFromTypeTree = track("typedSelectFromTypeTree") {
- val qual1 = typedType(tree.qualifier, selectionProto(tree.name, pt, this))
- cpy.SelectFromTypeTree(tree, qual1, tree.name).withType(checkedSelectionType(qual1, tree))
+ assignType(cpy.SingletonTypeTree(tree, ref1), ref1)
}
def typedAndTypeTree(tree: untpd.AndTypeTree)(implicit ctx: Context): AndTypeTree = track("typedAndTypeTree") {
val left1 = typed(tree.left)
val right1 = typed(tree.right)
- cpy.AndTypeTree(tree, left1, right1) withType left1.tpe & right1.tpe
+ assignType(cpy.AndTypeTree(tree, left1, right1), left1, right1)
}
def typedOrTypeTree(tree: untpd.OrTypeTree)(implicit ctx: Context): OrTypeTree = track("typedOrTypeTree") {
val left1 = typed(tree.left)
val right1 = typed(tree.right)
- cpy.OrTypeTree(tree, left1, right1) withType left1.tpe | right1.tpe
+ assignType(cpy.OrTypeTree(tree, left1, right1), left1, right1)
}
def typedRefinedTypeTree(tree: untpd.RefinedTypeTree)(implicit ctx: Context): RefinedTypeTree = track("typedRefinedTypeTree") {
@@ -828,16 +686,13 @@ class Typer extends Namer with Applications with Implicits {
def typedAppliedTypeTree(tree: untpd.AppliedTypeTree)(implicit ctx: Context): AppliedTypeTree = track("typedAppliedTypeTree") {
val tpt1 = typed(tree.tpt)
val args1 = tree.args mapconserve (typed(_))
- val tparams = tpt1.tpe.typeParams
- if (args1.length != tparams.length)
- ctx.error(i"wrong number of type arguments for ${tpt1.tpe}, should be ${tparams.length}")
// todo in later phase: check arguments conform to parameter bounds
- cpy.AppliedTypeTree(tree, tpt1, args1) withType tpt1.tpe.appliedTo(args1.tpes)
+ assignType(cpy.AppliedTypeTree(tree, tpt1, args1), tpt1, args1)
}
def typedByNameTypeTree(tree: untpd.ByNameTypeTree)(implicit ctx: Context): ByNameTypeTree = track("typedByNameTypeTree") {
val result1 = typed(tree.result)
- cpy.ByNameTypeTree(tree, result1) withType ExprType(result1.tpe)
+ assignType(cpy.ByNameTypeTree(tree, result1), result1)
}
def typedTypeBoundsTree(tree: untpd.TypeBoundsTree)(implicit ctx: Context): TypeBoundsTree = track("typedTypeBoundsTree") {
@@ -846,19 +701,19 @@ class Typer extends Namer with Applications with Implicits {
val hi1 = typed(hi)
if (!(lo1.tpe <:< hi1.tpe))
ctx.error(i"lower bound ${lo1.tpe} does not conform to upper bound ${hi1.tpe}", tree.pos)
- cpy.TypeBoundsTree(tree, lo1, hi1) withType TypeBounds(lo1.tpe, hi1.tpe)
+ assignType(cpy.TypeBoundsTree(tree, lo1, hi1), lo1, hi1)
}
def typedBind(tree: untpd.Bind, pt: Type)(implicit ctx: Context): Bind = track("typedBind") {
val body1 = typed(tree.body, pt)
typr.println(s"typed bind ${tree.show} pt = ${pt.show} bodytpe = ${body1.tpe.show}")
val sym = ctx.newSymbol(ctx.owner, tree.name.asTermName, EmptyFlags, body1.tpe, coord = tree.pos)
- cpy.Bind(tree, tree.name, body1) withType TermRef(NoPrefix, sym)
+ assignType(cpy.Bind(tree, tree.name, body1), sym)
}
def typedAlternative(tree: untpd.Alternative, pt: Type)(implicit ctx: Context): Alternative = track("typedAlternative") {
val trees1 = tree.trees mapconserve (typed(_, pt))
- cpy.Alternative(tree, trees1) withType ctx.typeComparer.lub(trees1.tpes)
+ assignType(cpy.Alternative(tree, trees1), trees1)
}
def typedModifiers(mods: untpd.Modifiers)(implicit ctx: Context): Modifiers = track("typedModifiers") {
@@ -880,8 +735,7 @@ class Typer extends Namer with Applications with Implicits {
case Ident(nme.WILDCARD) => rhs withType tpt1.tpe
case _ => typedExpr(rhs, tpt1.tpe)
}
- val refType = if (sym.exists) sym.valRef else NoType
- cpy.ValDef(vdef, mods1, name, tpt1, rhs1).withType(refType)
+ assignType(cpy.ValDef(vdef, mods1, name, tpt1, rhs1), sym)
}
def typedDefDef(ddef: untpd.DefDef, sym: Symbol)(implicit ctx: Context) = track("typedDefDef") {
@@ -895,7 +749,7 @@ class Typer extends Namer with Applications with Implicits {
}
val tpt1 = typedType(tpt)
val rhs1 = typedExpr(rhs, tpt1.tpe)
- cpy.DefDef(ddef, mods1, name, tparams1, vparamss1, tpt1, rhs1).withType(sym.termRefWithSig)
+ assignType(cpy.DefDef(ddef, mods1, name, tparams1, vparamss1, tpt1, rhs1), sym)
//todo: make sure dependent method types do not depend on implicits or by-name params
}
@@ -903,7 +757,7 @@ class Typer extends Namer with Applications with Implicits {
val TypeDef(mods, name, rhs) = tdef
val mods1 = typedModifiers(mods)
val _ = typedType(rhs) // unused, typecheck only to remove from typedTree
- cpy.TypeDef(tdef, mods1, name, TypeTree(sym.info)).withType(sym.typeRef)
+ assignType(cpy.TypeDef(tdef, mods1, name, TypeTree(sym.info)), sym)
}
def typedClassDef(cdef: untpd.TypeDef, cls: ClassSymbol)(implicit ctx: Context) = track("typedClassDef") {
@@ -938,7 +792,7 @@ class Typer extends Namer with Applications with Implicits {
checkNoDoubleDefs(cls)
val impl1 = cpy.Template(impl, constr1, parents1, self1, body1)
.withType(localDummy.termRef)
- cpy.TypeDef(cdef, mods1, name, impl1).withType(cls.typeRef)
+ assignType(cpy.TypeDef(cdef, mods1, name, impl1), cls)
// todo later: check that
// 1. If class is non-abstract, it is instantiatable:
@@ -952,23 +806,9 @@ class Typer extends Namer with Applications with Implicits {
def typedImport(imp: untpd.Import, sym: Symbol)(implicit ctx: Context): Import = track("typedImport") {
val expr1 = typedExpr(imp.expr, AnySelectionProto)
checkStable(expr1.tpe, imp.expr.pos)
- cpy.Import(imp, expr1, imp.selectors).withType(sym.termRef)
+ assignType(cpy.Import(imp, expr1, imp.selectors), sym)
}
- def typedAnnotated(tree: untpd.Annotated, pt: Type)(implicit ctx: Context): Tree = track("typedAnnotated") {
- val annot1 = typed(tree.annot, defn.AnnotationClass.typeRef)
- val arg1 = typed(tree.arg, pt)
- val underlyingType = if (arg1.isTerm) arg1.tpe.widen else arg1.tpe
- val ownType = AnnotatedType(Annotation(annot1), underlyingType)
- if (ctx.mode is Mode.Type)
- cpy.Annotated(tree, annot1, arg1) withType ownType
- else
- cpy.Typed(tree, arg1, TypeTree(ownType)) withType ownType
- }
-
- def typedAsFunction(tree: untpd.Tree, pt: Type)(implicit ctx: Context): Tree =
- typed(tree, if (defn.isFunctionType(pt)) pt else AnyFunctionProto)
-
def typedPackageDef(tree: untpd.PackageDef)(implicit ctx: Context): Tree = track("typedPackageDef") {
val pid1 = typedExpr(tree.pid, AnySelectionProto)
val pkg = pid1.symbol
@@ -982,6 +822,20 @@ class Typer extends Namer with Applications with Implicits {
cpy.PackageDef(tree, pid1.asInstanceOf[RefTree], stats1) withType pkg.valRef
}
+ def typedAnnotated(tree: untpd.Annotated, pt: Type)(implicit ctx: Context): Tree = track("typedAnnotated") {
+ val annot1 = typed(tree.annot, defn.AnnotationClass.typeRef)
+ val arg1 = typed(tree.arg, pt)
+ if (ctx.mode is Mode.Type)
+ assignType(cpy.Annotated(tree, annot1, arg1), annot1, arg1)
+ else {
+ val tpt = TypeTree(AnnotatedType(Annotation(annot1), arg1.tpe.widen))
+ assignType(cpy.Typed(tree, arg1, tpt), tpt)
+ }
+ }
+
+ def typedAsFunction(tree: untpd.Tree, pt: Type)(implicit ctx: Context): Tree =
+ typed(tree, if (defn.isFunctionType(pt)) pt else AnyFunctionProto)
+
def typedUnadapted(initTree: untpd.Tree, pt: Type = WildcardType)(implicit ctx: Context): Tree = {
record("typedUnadapted")
val xtree = expanded(initTree)