diff options
author | Martin Odersky <odersky@gmail.com> | 2013-07-25 22:16:07 +0200 |
---|---|---|
committer | Martin Odersky <odersky@gmail.com> | 2013-07-25 22:22:42 +0200 |
commit | cf65e84a6da2a151286a36297c057b72545960c8 (patch) | |
tree | 55f3d8a30f5751602836d62d0b1a4ae6269b64bd /src/dotty/tools/dotc | |
parent | 0a86c0ae8668070f62df25c7a4ba12369f23b216 (diff) | |
download | dotty-cf65e84a6da2a151286a36297c057b72545960c8.tar.gz dotty-cf65e84a6da2a151286a36297c057b72545960c8.tar.bz2 dotty-cf65e84a6da2a151286a36297c057b72545960c8.zip |
More typer logic, in particular dealing with variants of applications
Diffstat (limited to 'src/dotty/tools/dotc')
-rw-r--r-- | src/dotty/tools/dotc/ast/Desugar.scala | 3 | ||||
-rw-r--r-- | src/dotty/tools/dotc/ast/TreeInfo.scala | 5 | ||||
-rw-r--r-- | src/dotty/tools/dotc/ast/Trees.scala | 115 | ||||
-rw-r--r-- | src/dotty/tools/dotc/ast/UntypedTrees.scala | 36 | ||||
-rw-r--r-- | src/dotty/tools/dotc/core/Definitions.scala | 5 | ||||
-rw-r--r-- | src/dotty/tools/dotc/core/Types.scala | 29 | ||||
-rw-r--r-- | src/dotty/tools/dotc/printing/RefinedPrinter.scala | 6 | ||||
-rw-r--r-- | src/dotty/tools/dotc/typer/Applications.scala | 273 | ||||
-rw-r--r-- | src/dotty/tools/dotc/typer/ErrorReporting.scala | 13 | ||||
-rw-r--r-- | src/dotty/tools/dotc/typer/Inferencing.scala | 32 | ||||
-rw-r--r-- | src/dotty/tools/dotc/typer/Mode.scala | 1 | ||||
-rw-r--r-- | src/dotty/tools/dotc/typer/Namer.scala | 2 | ||||
-rw-r--r-- | src/dotty/tools/dotc/typer/Typer.scala | 137 |
13 files changed, 460 insertions, 197 deletions
diff --git a/src/dotty/tools/dotc/ast/Desugar.scala b/src/dotty/tools/dotc/ast/Desugar.scala index 2535e32ad..0a0638fa1 100644 --- a/src/dotty/tools/dotc/ast/Desugar.scala +++ b/src/dotty/tools/dotc/ast/Desugar.scala @@ -189,7 +189,8 @@ object desugar { else DefDef(synthetic, nme.apply, tparams, vparamss, EmptyTree, creatorExpr) :: Nil val unapplyMeth = { val unapplyParam = makeSyntheticParameter(tpt = classTypeRef) - DefDef(synthetic, nme.unapply, tparams, (unapplyParam :: Nil) :: Nil, EmptyTree, This(EmptyTypeName)) + DefDef(synthetic, nme.unapply, tparams, (unapplyParam :: Nil) :: Nil, + EmptyTree, Ident(unapplyParam.name)) } companionDefs(parent, applyMeths ::: unapplyMeth :: defaultGetters) } diff --git a/src/dotty/tools/dotc/ast/TreeInfo.scala b/src/dotty/tools/dotc/ast/TreeInfo.scala index e43fd66cb..cde8c10b0 100644 --- a/src/dotty/tools/dotc/ast/TreeInfo.scala +++ b/src/dotty/tools/dotc/ast/TreeInfo.scala @@ -47,6 +47,11 @@ abstract class TreeInfo { false } + def isOpAssign(tree: untpd.Tree) = tree match { + case Apply(Select(_, name), _ :: Nil) if name.isOpAssignmentName => true + case _ => false + } + /** Is tree an expression which can be inlined without affecting program semantics? * * Note that this is not called "isExprPure" since purity (lack of side-effects) diff --git a/src/dotty/tools/dotc/ast/Trees.scala b/src/dotty/tools/dotc/ast/Trees.scala index dc37d5655..2ae474d15 100644 --- a/src/dotty/tools/dotc/ast/Trees.scala +++ b/src/dotty/tools/dotc/ast/Trees.scala @@ -52,6 +52,9 @@ object Trees { newpd.asInstanceOf[this.type] } + def withPos(posd: Positioned): this.type = + if (posd == null) this else withPos(posd.pos) + /** This item with a position that's the union of the given `pos` and the * current position. */ @@ -150,33 +153,36 @@ object Trees { /** The type constructor at the root of the tree */ type ThisTree[T >: Untyped] <: Tree[T] - private var _tpe: T = _ + private var myTpe: T = _ /** The type of the tree. In case of an untyped tree, * an UnAssignedTypeException is thrown. (Overridden by empty trees) */ def tpe: T = { - if (_tpe == null) throw new UnAssignedTypeException(this) - _tpe + if (myTpe == null) throw new UnAssignedTypeException(this) + myTpe } /** Copy `tpe` attribute from tree `from` into this tree, independently * whether it is null or not. - */ - final def copyAttr(from: Tree[T]): ThisTree[T] = { - _tpe = from._tpe - this.withPos(from.pos).asInstanceOf[ThisTree[T]] + final def copyAttr[U >: Untyped](from: Tree[U]): ThisTree[T] = { + val t1 = this.withPos(from.pos) + val t2 = + if (from.myTpe != null) t1.withType(from.myTpe.asInstanceOf[Type]) + else t1 + t2.asInstanceOf[ThisTree[T]] } + */ /** Return a typed tree that's isomorphic to this tree, but has given * type. (Overridden by empty trees) */ def withType(tpe: Type): ThisTree[Type] = { val tree = - (if (_tpe == null || - (_tpe.asInstanceOf[AnyRef] eq tpe.asInstanceOf[AnyRef])) this + (if (myTpe == null || + (myTpe.asInstanceOf[AnyRef] eq tpe.asInstanceOf[AnyRef])) this else clone).asInstanceOf[Tree[Type]] - tree._tpe = tpe + tree.myTpe = tpe tree.asInstanceOf[ThisTree[Type]] } @@ -185,9 +191,9 @@ object Trees { * modifications. Should be used only in special circumstances (we * need it for printing trees with optional type info). */ - final def hasType: Boolean = _tpe != null + final def hasType: Boolean = myTpe != null - final def typeOpt: Type = _tpe match { + final def typeOpt: Type = myTpe match { case tp: Type => tp case _ => NoType } @@ -695,6 +701,7 @@ object Trees { type ValOrDefDef = Trees.ValOrDefDef[T] type Ident = Trees.Ident[T] + type BackquotedIdent = Trees.BackquotedIdent[T] type Select = Trees.Select[T] type This = Trees.This[T] type Super = Trees.Super[T] @@ -747,169 +754,169 @@ object Trees { def derivedIdent(name: Name): Ident[T] = tree match { case tree: BackquotedIdent[_] => if (name == tree.name) tree - else new BackquotedIdent[T](name).copyAttr(tree) + else new BackquotedIdent[T](name).withPos(tree.pos) case tree: Ident[_] if (name == tree.name) => tree - case _ => Ident[T](name).copyAttr(tree) + case _ => Ident[T](name).withPos(tree.pos) } def derivedSelect(qualifier: Tree[T], name: Name): Select[T] = tree match { case tree: Select[_] if (qualifier eq tree.qualifier) && (name == tree.name) => tree - case _ => Select(qualifier, name).copyAttr(tree) + case _ => Select(qualifier, name).withPos(tree.pos) } def derivedThis(qual: TypeName): This[T] = tree match { case tree: This[_] if (qual == tree.qual) => tree - case _ => This[T](qual).copyAttr(tree) + case _ => This[T](qual).withPos(tree.pos) } def derivedSuper(qual: Tree[T], mix: TypeName): Super[T] = tree match { case tree: Super[_] if (qual eq tree.qual) && (mix == tree.mix) => tree - case _ => Super(qual, mix).copyAttr(tree) + case _ => Super(qual, mix).withPos(tree.pos) } def derivedApply(fun: Tree[T], args: List[Tree[T]]): Apply[T] = tree match { case tree: Apply[_] if (fun eq tree.fun) && (args eq tree.args) => tree - case _ => Apply(fun, args).copyAttr(tree) + case _ => Apply(fun, args).withPos(tree.pos) } def derivedTypeApply(fun: Tree[T], args: List[Tree[T]]): TypeApply[T] = tree match { case tree: TypeApply[_] if (fun eq tree.fun) && (args eq tree.args) => tree - case _ => TypeApply(fun, args).copyAttr(tree) + case _ => TypeApply(fun, args).withPos(tree) } def derivedLiteral(const: Constant): Literal[T] = tree match { case tree: Literal[_] if (const == tree.const) => tree - case _ => Literal[T](const).copyAttr(tree) + case _ => Literal[T](const).withPos(tree.pos) } def derivedNew(tpt: Tree[T]): New[T] = tree match { case tree: New[_] if (tpt eq tree.tpt) => tree - case _ => New(tpt).copyAttr(tree) + case _ => New(tpt).withPos(tree.pos) } def derivedPair(left: Tree[T], right: Tree[T]): Pair[T] = tree match { case tree: Pair[_] if (left eq tree.left) && (right eq tree.right) => tree - case _ => Pair(left, right).copyAttr(tree) + case _ => Pair(left, right).withPos(tree.pos) } def derivedTyped(expr: Tree[T], tpt: Tree[T]): Typed[T] = tree match { case tree: Typed[_] if (expr eq tree.expr) && (tpt eq tree.tpt) => tree - case _ => Typed(expr, tpt).copyAttr(tree) + case _ => Typed(expr, tpt).withPos(tree.pos) } def derivedNamedArg(name: Name, arg: Tree[T]): NamedArg[T] = tree match { case tree: NamedArg[_] if (name == tree.name) && (arg eq tree.arg) => tree - case _ => NamedArg(name, arg).copyAttr(tree) + case _ => NamedArg(name, arg).withPos(tree.pos) } def derivedAssign(lhs: Tree[T], rhs: Tree[T]): Assign[T] = tree match { case tree: Assign[_] if (lhs eq tree.lhs) && (rhs eq tree.rhs) => tree - case _ => Assign(lhs, rhs).copyAttr(tree) + case _ => Assign(lhs, rhs).withPos(tree.pos) } def derivedBlock(stats: List[Tree[T]], expr: Tree[T]): Block[T] = tree match { case tree: Block[_] if (stats eq tree.stats) && (expr eq tree.expr) => tree - case _ => Block(stats, expr).copyAttr(tree) + case _ => Block(stats, expr).withPos(tree.pos) } def derivedIf(cond: Tree[T], thenp: Tree[T], elsep: Tree[T]): If[T] = tree match { case tree: If[_] if (cond eq tree.cond) && (thenp eq tree.thenp) && (elsep eq tree.elsep) => tree - case _ => If(cond, thenp, elsep).copyAttr(tree) + case _ => If(cond, thenp, elsep).withPos(tree.pos) } def derivedClosure(env: List[Tree[T]], meth: RefTree[T]): Closure[T] = tree match { case tree: Closure[_] if (env eq tree.env) && (meth eq tree.meth) => tree - case _ => Closure(env, meth).copyAttr(tree) + case _ => Closure(env, meth).withPos(tree.pos) } def derivedMatch(selector: Tree[T], cases: List[CaseDef[T]]): Match[T] = tree match { case tree: Match[_] if (selector eq tree.selector) && (cases eq tree.cases) => tree - case _ => Match(selector, cases).copyAttr(tree) + case _ => Match(selector, cases).withPos(tree.pos) } def derivedCaseDef(pat: Tree[T], guard: Tree[T], body: Tree[T]): CaseDef[T] = tree match { case tree: CaseDef[_] if (pat eq tree.pat) && (guard eq tree.guard) && (body eq tree.body) => tree - case _ => CaseDef(pat, guard, body).copyAttr(tree) + case _ => CaseDef(pat, guard, body).withPos(tree.pos) } def derivedReturn(expr: Tree[T], from: Tree[T]): Return[T] = tree match { case tree: Return[_] if (expr eq tree.expr) && (from eq tree.from) => tree - case _ => Return(expr, from).copyAttr(tree) + case _ => Return(expr, from).withPos(tree.pos) } def derivedTry(expr: Tree[T], handler: Tree[T], finalizer: Tree[T]): Try[T] = tree match { case tree: Try[_] if (expr eq tree.expr) && (handler eq tree.handler) && (finalizer eq tree.finalizer) => tree - case _ => Try(expr, handler, finalizer).copyAttr(tree) + case _ => Try(expr, handler, finalizer).withPos(tree.pos) } def derivedThrow(expr: Tree[T]): Throw[T] = tree match { case tree: Throw[_] if (expr eq tree.expr) => tree - case _ => Throw(expr).copyAttr(tree) + case _ => Throw(expr).withPos(tree.pos) } def derivedSeqLiteral(elems: List[Tree[T]]): SeqLiteral[T] = tree match { case tree: SeqLiteral[_] if (elems eq tree.elems) => tree - case _ => SeqLiteral(elems).copyAttr(tree) + case _ => SeqLiteral(elems).withPos(tree.pos) } def derivedSingletonTypeTree(ref: Tree[T]): SingletonTypeTree[T] = tree match { case tree: SingletonTypeTree[_] if (ref eq tree.ref) => tree - case _ => SingletonTypeTree(ref).copyAttr(tree) + case _ => SingletonTypeTree(ref).withPos(tree.pos) } def derivedSelectFromTypeTree(qualifier: Tree[T], name: Name): SelectFromTypeTree[T] = tree match { case tree: SelectFromTypeTree[_] if (qualifier eq tree.qualifier) && (name == tree.name) => tree - case _ => SelectFromTypeTree(qualifier, name).copyAttr(tree) + case _ => SelectFromTypeTree(qualifier, name).withPos(tree.pos) } def derivedAndTypeTree(left: Tree[T], right: Tree[T]): AndTypeTree[T] = tree match { case tree: AndTypeTree[_] if (left eq tree.left) && (right eq tree.right) => tree - case _ => AndTypeTree(left, right).copyAttr(tree) + case _ => AndTypeTree(left, right).withPos(tree.pos) } def derivedOrTypeTree(left: Tree[T], right: Tree[T]): OrTypeTree[T] = tree match { case tree: OrTypeTree[_] if (left eq tree.left) && (right eq tree.right) => tree - case _ => OrTypeTree(left, right).copyAttr(tree) + case _ => OrTypeTree(left, right).withPos(tree.pos) } def derivedRefinedTypeTree(tpt: Tree[T], refinements: List[Tree[T]]): RefinedTypeTree[T] = tree match { case tree: RefinedTypeTree[_] if (tpt eq tree.tpt) && (refinements eq tree.refinements) => tree - case _ => RefinedTypeTree(tpt, refinements).copyAttr(tree) + case _ => RefinedTypeTree(tpt, refinements).withPos(tree.pos) } def derivedAppliedTypeTree(tpt: Tree[T], args: List[Tree[T]]): AppliedTypeTree[T] = tree match { case tree: AppliedTypeTree[_] if (tpt eq tree.tpt) && (args eq tree.args) => tree - case _ => AppliedTypeTree(tpt, args).copyAttr(tree) + case _ => AppliedTypeTree(tpt, args).withPos(tree.pos) } def derivedTypeBoundsTree(lo: Tree[T], hi: Tree[T]): TypeBoundsTree[T] = tree match { case tree: TypeBoundsTree[_] if (lo eq tree.lo) && (hi eq tree.hi) => tree - case _ => TypeBoundsTree(lo, hi).copyAttr(tree) + case _ => TypeBoundsTree(lo, hi).withPos(tree.pos) } def derivedBind(name: Name, body: Tree[T]): Bind[T] = tree match { case tree: Bind[_] if (name eq tree.name) && (body eq tree.body) => tree - case _ => Bind(name, body).copyAttr(tree) + case _ => Bind(name, body).withPos(tree.pos) } def derivedAlternative(trees: List[Tree[T]]): Alternative[T] = tree match { case tree: Alternative[_] if (trees eq tree.trees) => tree - case _ => Alternative(trees).copyAttr(tree) + case _ => Alternative(trees).withPos(tree.pos) } def derivedUnApply(fun: Tree[T], args: List[Tree[T]]): UnApply[T] = tree match { case tree: UnApply[_] if (fun eq tree.fun) && (args eq tree.args) => tree - case _ => UnApply(fun, args).copyAttr(tree) + case _ => UnApply(fun, args).withPos(tree.pos) } def derivedValDef(mods: Modifiers[T], name: TermName, tpt: Tree[T], rhs: Tree[T]): ValDef[T] = tree match { case tree: ValDef[_] if (mods == tree.mods) && (name == tree.name) && (tpt eq tree.tpt) && (rhs eq tree.rhs) => tree - case _ => ValDef(mods, name, tpt, rhs).copyAttr(tree) + case _ => ValDef(mods, name, tpt, rhs).withPos(tree.pos) } def derivedDefDef(mods: Modifiers[T], name: TermName, tparams: List[TypeDef[T]], vparamss: List[List[ValDef[T]]], tpt: Tree[T], rhs: Tree[T]): DefDef[T] = tree match { case tree: DefDef[_] if (mods == tree.mods) && (name == tree.name) && (tparams eq tree.tparams) && (vparamss eq tree.vparamss) && (tpt eq tree.tpt) && (rhs eq tree.rhs) => tree - case _ => DefDef(mods, name, tparams, vparamss, tpt, rhs).copyAttr(tree) + case _ => DefDef(mods, name, tparams, vparamss, tpt, rhs).withPos(tree.pos) } def derivedTypeDef(mods: Modifiers[T], name: TypeName, rhs: Tree[T], tparams: List[untpd.TypeDef] = Nil): TypeDef[T] = tree match { case tree: TypeDef[_] if (mods == tree.mods) && (name == tree.name) && (rhs eq tree.rhs) && (tparams eq tree.tparams) => tree case _ => if (tparams.nonEmpty) (untpd.typeDef _).asInstanceOf[(Modifiers[T], TypeName, List[untpd.TypeDef], Tree[T]) => TypeDef[T]]( - mods, name, tparams, rhs).copyAttr(tree) - else TypeDef(mods, name, rhs).copyAttr(tree) + mods, name, tparams, rhs).withPos(tree.pos) + else TypeDef(mods, name, rhs).withPos(tree.pos) } def derivedTemplate(constr: DefDef[T], parents: List[Tree[T]], self: ValDef[T], body: List[Tree[T]]): Template[T] = tree match { case tree: Template[_] if (constr eq tree.constr) && (parents eq tree.parents) && (self eq tree.self) && (body eq tree.body) => tree - case _ => Template(constr, parents, self, body).copyAttr(tree) + case _ => Template(constr, parents, self, body).withPos(tree.pos) } def derivedImport(expr: Tree[T], selectors: List[Tree[Untyped]]): Import[T] = tree match { case tree: Import[_] if (expr eq tree.expr) && (selectors eq tree.selectors) => tree - case _ => Import(expr, selectors).copyAttr(tree) + case _ => Import(expr, selectors).withPos(tree.pos) } def derivedPackageDef(pid: RefTree[T], stats: List[Tree[T]]): PackageDef[T] = tree match { case tree: PackageDef[_] if (pid eq tree.pid) && (stats eq tree.stats) => tree - case _ => PackageDef(pid, stats).copyAttr(tree) + case _ => PackageDef(pid, stats).withPos(tree.pos) } def derivedAnnotated(annot: Tree[T], arg: Tree[T]): Annotated[T] = tree match { case tree: Annotated[_] if (annot eq tree.annot) && (arg eq tree.arg) => tree - case _ => Annotated(annot, arg).copyAttr(tree) + case _ => Annotated(annot, arg).withPos(tree.pos) } def derivedSharedTree(shared: Tree[T]): SharedTree[T] = tree match { case tree: SharedTree[_] if (shared eq tree.shared) => tree - case _ => SharedTree(shared).copyAttr(tree) + case _ => SharedTree(shared).withPos(tree.pos) } def derivedThicket(trees: List[Tree[T]]): Thicket[T] = tree match { case tree: Thicket[_] if (trees eq tree.trees) => tree - case _ => Thicket(trees).copyAttr(tree) + case _ => Thicket(trees).withPos(tree.pos) } } diff --git a/src/dotty/tools/dotc/ast/UntypedTrees.scala b/src/dotty/tools/dotc/ast/UntypedTrees.scala index dacf13510..9449392dd 100644 --- a/src/dotty/tools/dotc/ast/UntypedTrees.scala +++ b/src/dotty/tools/dotc/ast/UntypedTrees.scala @@ -105,75 +105,75 @@ object untpd extends Trees.Instance[Untyped] { implicit class UntypedTreeCopier(val tree: Tree) extends AnyVal { def derivedModuleDef(mods: Modifiers, name: TermName, impl: Template) = tree match { case tree: ModuleDef if (mods eq tree.mods) && (name eq tree.name) && (impl eq tree.impl) => tree - case _ => ModuleDef(mods, name, impl).copyAttr(tree) + case _ => ModuleDef(mods, name, impl).withPos(tree.pos) } def derivedPolyTypeDef(mods: Modifiers, name: TypeName, tparams: List[TypeDef], rhs: Tree) = tree match { case tree: PolyTypeDef if (mods eq tree.mods) && (name eq tree.name) && (tparams eq tree.tparams) && (rhs eq tree.rhs) => tree - case _ => new PolyTypeDef(mods, name, tparams, rhs).copyAttr(tree) + case _ => new PolyTypeDef(mods, name, tparams, rhs).withPos(tree.pos) } def derivedSymbolLit(str: String) = tree match { case tree: SymbolLit if (str == tree.str) => tree - case _ => SymbolLit(str).copyAttr(tree) + case _ => SymbolLit(str).withPos(tree.pos) } def derivedInterpolatedString(id: TermName, strings: List[Literal], elems: List[Tree]) = tree match { case tree: InterpolatedString if (id eq tree.id) && (strings eq tree.strings) && (elems eq tree.elems) => tree - case _ => InterpolatedString(id, strings, elems).copyAttr(tree) + case _ => InterpolatedString(id, strings, elems).withPos(tree.pos) } def derivedFunction(args: List[Tree], body: Tree) = tree match { case tree: Function if (args eq tree.args) && (body eq tree.body) => tree - case _ => Function(args, body).copyAttr(tree) + case _ => Function(args, body).withPos(tree.pos) } def derivedInfixOp(left: Tree, op: Name, right: Tree) = tree match { case tree: InfixOp if (left eq tree.left) && (op eq tree.op) && (right eq tree.right) => tree - case _ => InfixOp(left, op, right).copyAttr(tree) + case _ => InfixOp(left, op, right).withPos(tree.pos) } def derivedPostfixOp(od: Tree, op: Name) = tree match { case tree: PostfixOp if (od eq tree.od) && (op eq tree.op) => tree - case _ => PostfixOp(od, op).copyAttr(tree) + case _ => PostfixOp(od, op).withPos(tree.pos) } def derivedPrefixOp(op: Name, od: Tree) = tree match { case tree: PrefixOp if (op eq tree.op) && (od eq tree.od) => tree - case _ => PrefixOp(op, od).copyAttr(tree) + case _ => PrefixOp(op, od).withPos(tree.pos) } def derivedParens(t: Tree) = tree match { case tree: Parens if (t eq tree.t) => tree - case _ => Parens(t).copyAttr(tree) + case _ => Parens(t).withPos(tree.pos) } def derivedTuple(trees: List[Tree]) = tree match { case tree: Tuple if (trees eq tree.trees) => tree - case _ => Tuple(trees).copyAttr(tree) + case _ => Tuple(trees).withPos(tree.pos) } def derivedWhileDo(cond: Tree, body: Tree) = tree match { case tree: WhileDo if (cond eq tree.cond) && (body eq tree.body) => tree - case _ => WhileDo(cond, body).copyAttr(tree) + case _ => WhileDo(cond, body).withPos(tree.pos) } def derivedDoWhile(body: Tree, cond: Tree) = tree match { case tree: DoWhile if (body eq tree.body) && (cond eq tree.cond) => tree - case _ => DoWhile(body, cond).copyAttr(tree) + case _ => DoWhile(body, cond).withPos(tree.pos) } def derivedForYield(enums: List[Tree], expr: Tree) = tree match { case tree: ForYield if (enums eq tree.enums) && (expr eq tree.expr) => tree - case _ => ForYield(enums, expr).copyAttr(tree) + case _ => ForYield(enums, expr).withPos(tree.pos) } def derivedForDo(enums: List[Tree], body: Tree) = tree match { case tree: ForDo if (enums eq tree.enums) && (body eq tree.body) => tree - case _ => ForDo(enums, body).copyAttr(tree) + case _ => ForDo(enums, body).withPos(tree.pos) } def derivedGenFrom(pat: Tree, expr: Tree) = tree match { case tree: GenFrom if (pat eq tree.pat) && (expr eq tree.expr) => tree - case _ => GenFrom(pat, expr).copyAttr(tree) + case _ => GenFrom(pat, expr).withPos(tree.pos) } def derivedGenAlias(pat: Tree, expr: Tree) = tree match { case tree: GenAlias if (pat eq tree.pat) && (expr eq tree.expr) => tree - case _ => GenAlias(pat, expr).copyAttr(tree) + case _ => GenAlias(pat, expr).withPos(tree.pos) } def derivedContextBounds(bounds: TypeBoundsTree, cxBounds: List[Tree]) = tree match { case tree: ContextBounds if (bounds eq tree.bounds) && (cxBounds eq tree.cxBounds) => tree - case _ => ContextBounds(bounds, cxBounds).copyAttr(tree) + case _ => ContextBounds(bounds, cxBounds).withPos(tree.pos) } def derivedPatDef(mods: Modifiers, pats: List[Tree], tpt: Tree, rhs: Tree) = tree match { case tree: PatDef if (mods eq tree.mods) && (pats eq tree.pats) && (tpt eq tree.tpt) && (rhs eq tree.rhs) => tree - case _ => PatDef(mods, pats, tpt, rhs).copyAttr(tree) + case _ => PatDef(mods, pats, tpt, rhs).withPos(tree.pos) } } diff --git a/src/dotty/tools/dotc/core/Definitions.scala b/src/dotty/tools/dotc/core/Definitions.scala index 41d032f7a..bde325897 100644 --- a/src/dotty/tools/dotc/core/Definitions.scala +++ b/src/dotty/tools/dotc/core/Definitions.scala @@ -181,7 +181,7 @@ class Definitions(implicit ctx: Context) { lazy val RepeatedParamAlias = newAliasType(tpnme.REPEATED_PARAM_CLASS, SeqType) lazy val JavaRepeatedParamAlias = newAliasType(tpnme.JAVA_REPEATED_PARAM_CLASS, ArrayType) - // fundamental reference classes + // fundamental classes lazy val StringClass = requiredClass("java.lang.String") lazy val String_+ = newMethod(StringClass, nme.raw.PLUS, methOfAny(StringType), Final) @@ -202,6 +202,7 @@ class Definitions(implicit ctx: Context) { lazy val ThrowableClass = requiredClass("java.lang.Throwable") lazy val JavaSerializableClass = requiredClass("java.lang.Serializable") lazy val ComparableClass = requiredClass("java.lang.Comparable") + lazy val ProductClass = requiredClass("scala.Product") // Annotation base classes lazy val AnnotationClass = requiredClass("scala.annotation.Annotation") @@ -286,9 +287,11 @@ class Definitions(implicit ctx: Context) { lazy val FunctionClass = mkArityArray("Function", MaxFunctionArity, 0) lazy val TupleClass = mkArityArray("Tuple", MaxTupleArity, 2) + lazy val ProductNClass = mkArityArray("Product", MaxTupleArity, 2) lazy val FunctionClasses: Set[Symbol] = FunctionClass.toSet lazy val TupleClasses: Set[Symbol] = TupleClass.toSet + lazy val ProductClasses: Set[Symbol] = ProductNClass.toSet lazy val RepeatedParamAliases: Set[Symbol] = Set(RepeatedParamAlias, JavaRepeatedParamAlias) diff --git a/src/dotty/tools/dotc/core/Types.scala b/src/dotty/tools/dotc/core/Types.scala index 468c5f58a..c3e15d94c 100644 --- a/src/dotty/tools/dotc/core/Types.scala +++ b/src/dotty/tools/dotc/core/Types.scala @@ -579,6 +579,15 @@ object Types { case _ => List() } + def firstParent(implicit ctx: Context): TypeRef = this match { + case tp: TypeProxy => tp.underlying.firstParent + case _ => + parents match { + case p :: _ => p + case _ => defn.AnyClass.symTypeRef + } + } + /** The parameter types of a PolyType or MethodType, Empty list for others */ final def paramTypess: List[List[Type]] = this match { case mt: MethodType => mt.paramTypes :: mt.resultType.paramTypess @@ -1428,7 +1437,7 @@ object Types { } def instantiate(argTypes: => List[Type])(implicit ctx: Context): Type = - if (isDependent) new InstMethodMap(this, argTypes) apply resultType + if (isDependent) resultType.substParams(this, argTypes) else resultType /* probably won't be needed @@ -1530,10 +1539,10 @@ object Types { override def signature(implicit ctx: Context) = resultType.signature def instantiate(argTypes: List[Type])(implicit ctx: Context): Type = - new InstPolyMap(this, argTypes) apply resultType + resultType.substParams(this, argTypes) def instantiateBounds(argTypes: List[Type])(implicit ctx: Context): List[TypeBounds] = - paramBounds.mapConserve(new InstPolyMap(this, argTypes).apply(_).bounds) + paramBounds.mapConserve(_.substParams(this, argTypes).bounds) def derivedPolyType(paramNames: List[TypeName], paramBounds: List[TypeBounds], restpe: Type)(implicit ctx: Context) = if ((paramNames eq this.paramNames) && (paramBounds eq this.paramBounds) && (restpe eq this.resultType)) this @@ -1953,20 +1962,6 @@ object Types { def apply(tp: Type) = tp } - class InstMethodMap(mt: MethodType, argtypes: List[Type])(implicit ctx: Context) extends TypeMap { - def apply(tp: Type) = tp match { - case MethodParam(`mt`, n) => argtypes(n) - case _ => mapOver(tp) - } - } - - class InstPolyMap(pt: PolyType, argtypes: List[Type])(implicit ctx: Context) extends TypeMap { - def apply(tp: Type) = tp match { - case PolyParam(`pt`, n) => argtypes(n) - case _ => mapOver(tp) - } - } - /** Approximate occurrences of paremter types and uninstantiated typevars * by wildcard types */ diff --git a/src/dotty/tools/dotc/printing/RefinedPrinter.scala b/src/dotty/tools/dotc/printing/RefinedPrinter.scala index bd16f97aa..d0b9dc6bd 100644 --- a/src/dotty/tools/dotc/printing/RefinedPrinter.scala +++ b/src/dotty/tools/dotc/printing/RefinedPrinter.scala @@ -5,8 +5,8 @@ import core._ import Texts._, Types._, Flags._, Names._, Symbols._, NameOps._, Constants._ import Contexts.Context, Scopes.Scope, Denotations.Denotation, Annotations.Annotation import StdNames.nme -import ast.Trees._ -import ast.untpd +import ast.{Trees, untpd} +import Trees._ import scala.annotation.switch class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) { @@ -135,7 +135,7 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) { import untpd._ val txt: Text = tree match { - case id: BackquotedIdent[_] => + case id: Trees.BackquotedIdent[_] => "`" ~ toText(id.name) ~ "`" case Ident(name) => toText(name) diff --git a/src/dotty/tools/dotc/typer/Applications.scala b/src/dotty/tools/dotc/typer/Applications.scala index f4b8d8b12..3ce735c12 100644 --- a/src/dotty/tools/dotc/typer/Applications.scala +++ b/src/dotty/tools/dotc/typer/Applications.scala @@ -13,7 +13,10 @@ import Denotations._ import NameOps._ import Symbols._ import Types._ +import Typer.TreeDecorator import Decorators._ +import ErrorReporting._ +import Trees._ import Names._ import StdNames._ import Constants._ @@ -24,6 +27,8 @@ import language.implicitConversions object Applications { + import tpd._ + private val isNamedArg = (arg: Any) => arg.isInstanceOf[Trees.NamedArg[_]] def hasNamedArg(args: List[Any]) = args exists isNamedArg @@ -61,16 +66,18 @@ object Applications { } case class FunProtoType(args: List[untpd.Tree], override val resultType: Type, typer: Typer)(implicit ctx: Context) extends UncachedGroundType { - private var myTypedArgs: List[tpd.Tree] = null + private var myTypedArgs: List[Tree] = null def argsAreTyped: Boolean = myTypedArgs != null - def typedArgs: List[tpd.Tree] = { + def typedArgs: List[Tree] = { if (myTypedArgs == null) myTypedArgs = args mapconserve (typer.typed(_)) myTypedArgs } } + + case class PolyProtoType(nargs: Int, override val resultType: Type) extends UncachedGroundType } import Applications._ @@ -78,7 +85,7 @@ import Applications._ trait Applications extends Compatibility{ self: Typer => import Applications._ - import Trees._ + import tpd._ private def state(implicit ctx: Context) = ctx.typerState @@ -100,7 +107,7 @@ trait Applications extends Compatibility{ self: Typer => protected def typedArg(arg: Arg, formal: Type): TypedArg /** Turn a typed tree into an argument */ - protected def treeToArg(arg: tpd.Tree): Arg + protected def treeToArg(arg: Tree): Arg /** Check that argument corresponds to type `formal` and * possibly add it to the list of adapted arguments @@ -126,7 +133,7 @@ trait Applications extends Compatibility{ self: Typer => /** If constructing trees, the current function part, which might be * affected by lifting. EmptyTree otherwise. */ - protected def normalizedFun: tpd.Tree + protected def normalizedFun: Tree /** If constructing trees, pull out all parts of the function * which are not idempotent into separate prefix definitions @@ -175,11 +182,11 @@ trait Applications extends Compatibility{ self: Typer => private def methString: String = s"method ${methRef.name}: ${methType.show}" /** Re-order arguments to correctly align named arguments */ - def reorder[T >: Untyped](args: List[Tree[T]]): List[Tree[T]] = { - var namedToArg: Map[Name, Tree[T]] = + def reorder[T >: Untyped](args: List[Trees.Tree[T]]): List[Trees.Tree[T]] = { + var namedToArg: Map[Name, Trees.Tree[T]] = (for (NamedArg(name, arg1) <- args) yield (name, arg1)).toMap - def badNamedArg(arg: Tree[_ >: Untyped]): Unit = { + def badNamedArg(arg: Trees.Tree[_ >: Untyped]): Unit = { val NamedArg(name, _) = arg def msg = if (methodType.paramNames contains name) @@ -189,7 +196,7 @@ trait Applications extends Compatibility{ self: Typer => fail(msg, arg.asInstanceOf[Arg]) } - def recur(pnames: List[Name], args: List[Tree[T]]): List[Tree[T]] = pnames match { + def recur(pnames: List[Name], args: List[Trees.Tree[T]]): List[Trees.Tree[T]] = pnames match { case pname :: pnames1 => namedToArg get pname match { case Some(arg) => @@ -223,9 +230,9 @@ trait Applications extends Compatibility{ self: Typer => } /** Splice new method reference into existing application */ - def spliceMeth(meth: tpd.Tree, app: tpd.Tree): tpd.Tree = app match { - case Apply(fn, args) => tpd.Apply(spliceMeth(meth, fn), args) - case TypeApply(fn, targs) => tpd.TypeApply(spliceMeth(meth, fn), targs) + def spliceMeth(meth: Tree, app: Tree): Tree = app match { + case Apply(fn, args) => Apply(spliceMeth(meth, fn), args) + case TypeApply(fn, targs) => TypeApply(spliceMeth(meth, fn), targs) case _ => meth } @@ -285,7 +292,7 @@ trait Applications extends Compatibility{ self: Typer => findDefaultGetter(n + TreeInfo.numArgs(normalizedFun)) match { case dref: NamedType => liftFun() - addTyped(treeToArg(spliceMeth(tpd.Ident(dref), normalizedFun)), formal) + addTyped(treeToArg(spliceMeth(Ident(dref), normalizedFun)), formal) matchArgs(args1, formals1, n + 1) case _ => missingArg(n) @@ -362,29 +369,29 @@ trait Applications extends Compatibility{ self: Typer => ok = false def fail(msg: => String) = ok = false - def normalizedFun = tpd.EmptyTree + def normalizedFun = EmptyTree } /** Subtrait of Application for the cases where arguments are (typed or * untyped) trees. */ - trait TreeApplication[T >: Untyped] extends Application[Tree[T]] { - type TypeArg = tpd.Tree - def isVarArg(arg: Tree[T]): Boolean = TreeInfo.isWildcardStarArg(arg) + trait TreeApplication[T >: Untyped] extends Application[Trees.Tree[T]] { + type TypeArg = Tree + def isVarArg(arg: Trees.Tree[T]): Boolean = TreeInfo.isWildcardStarArg(arg) } /** Subclass of Application for applicability tests with trees as arguments. */ - class ApplicableToTrees(methRef: TermRef, args: List[tpd.Tree], resultType: Type)(implicit ctx: Context) + class ApplicableToTrees(methRef: TermRef, args: List[Tree], resultType: Type)(implicit ctx: Context) extends TestApplication(methRef, methRef, args, resultType) with TreeApplication[Type] { - def argType(arg: tpd.Tree): Type = normalize(arg.tpe) - def treeToArg(arg: tpd.Tree): tpd.Tree = arg + def argType(arg: Tree): Type = normalize(arg.tpe) + def treeToArg(arg: Tree): Tree = arg } /** Subclass of Application for applicability tests with types as arguments. */ class ApplicableToTypes(methRef: TermRef, args: List[Type], resultType: Type)(implicit ctx: Context) extends TestApplication(methRef, methRef, args, resultType) { def argType(arg: Type): Type = arg - def treeToArg(arg: tpd.Tree): Type = arg.tpe + def treeToArg(arg: Tree): Type = arg.tpe def isVarArg(arg: Type): Boolean = arg.isRepeatedParam } @@ -392,24 +399,24 @@ trait Applications extends Compatibility{ self: Typer => * types of arguments are either known or unknown. */ abstract class TypedApply[T >: Untyped]( - app: untpd.Apply, fun: tpd.Tree, methRef: TermRef, args: List[Tree[T]], resultType: Type)(implicit ctx: Context) + app: untpd.Apply, fun: Tree, methRef: TermRef, args: List[Trees.Tree[T]], resultType: Type)(implicit ctx: Context) extends Application(methRef, fun.tpe, args, resultType) with TreeApplication[T] { - type TypedArg = tpd.Tree - private var typedArgBuf = new mutable.ListBuffer[tpd.Tree] - private var liftedDefs: mutable.ListBuffer[tpd.Tree] = null - private var myNormalizedFun: tpd.Tree = fun + type TypedArg = Tree + private var typedArgBuf = new mutable.ListBuffer[Tree] + private var liftedDefs: mutable.ListBuffer[Tree] = null + private var myNormalizedFun: Tree = fun - def addArg(arg: tpd.Tree, formal: Type): Unit = + def addArg(arg: Tree, formal: Type): Unit = typedArgBuf += adapt(arg, formal) def makeVarArg(n: Int, elemFormal: Type): Unit = { val args = typedArgBuf.takeRight(n).toList typedArgBuf.trimEnd(n) val seqType = if (methodType.isJava) defn.ArrayType else defn.SeqType - typedArgBuf += tpd.SeqLiteral(seqType.appliedTo(elemFormal :: Nil), args) + typedArgBuf += SeqLiteral(seqType.appliedTo(elemFormal :: Nil), args) } - def fail(msg: => String, arg: Tree[T]) = { + def fail(msg: => String, arg: Trees.Tree[T]) = { ctx.error(msg, arg.pos) ok = false } @@ -423,7 +430,7 @@ trait Applications extends Compatibility{ self: Typer => override def liftFun(): Unit = if (liftedDefs == null) { - liftedDefs = new mutable.ListBuffer[tpd.Tree] + liftedDefs = new mutable.ListBuffer[Tree] myNormalizedFun = liftApp(liftedDefs, myNormalizedFun) } @@ -431,7 +438,7 @@ trait Applications extends Compatibility{ self: Typer => * where `EmptyTree`s in the second list are skipped. * -1 if there are no differences. */ - private def firstDiff[T <: Tree[_]](xs: List[T], ys: List[T], n: Int = 0): Int = xs match { + private def firstDiff[T <: Trees.Tree[_]](xs: List[T], ys: List[T], n: Int = 0): Int = xs match { case x :: xs1 => ys match { case EmptyTree :: ys1 => firstDiff(xs1, ys1, n) @@ -445,53 +452,183 @@ trait Applications extends Compatibility{ self: Typer => case nil => -1 } } - def sameSeq[T <: Tree[_]](xs: List[T], ys: List[T]): Boolean = firstDiff(xs, ys) < 0 - - val result: tpd.Tree = - if (!success) app withType ErrorType - else { - var typedArgs = typedArgBuf.toList - if (!sameSeq(app.args, orderedArgs)) { - // need to lift arguments to maintain evaluation order in the - // presence of argument reorderings. - liftFun() - val eqSuffixLength = firstDiff(app.args.reverse, orderedArgs.reverse) - val (liftable, rest) = typedArgs splitAt (typedArgs.length - eqSuffixLength) - typedArgs = liftArgs(liftedDefs, methType, liftable) ++ rest + def sameSeq[T <: Trees.Tree[_]](xs: List[T], ys: List[T]): Boolean = firstDiff(xs, ys) < 0 + + val result = { + var typedArgs = typedArgBuf.toList + val ownType = + if (!success) ErrorType + else { + if (!sameSeq(app.args, orderedArgs)) { + // need to lift arguments to maintain evaluation order in the + // presence of argument reorderings. + liftFun() + val eqSuffixLength = firstDiff(app.args.reverse, orderedArgs.reverse) + val (liftable, rest) = typedArgs splitAt (typedArgs.length - eqSuffixLength) + typedArgs = liftArgs(liftedDefs, methType, liftable) ++ rest + } + if (sameSeq(typedArgs, args)) // trick to cut down on tree copying + typedArgs = args.asInstanceOf[List[Tree]] + methodType.instantiate(typedArgs map (_.tpe)) } - if (sameSeq(typedArgs, args)) // trick to cut down on tree copying - typedArgs = args.asInstanceOf[List[tpd.Tree]] - val app1 = app.withType(methodType.instantiate(typedArgs map (_.tpe))) - .derivedApply(normalizedFun, typedArgs) - if (liftedDefs != null && liftedDefs.nonEmpty) tpd.Block(liftedDefs.toList, app1) - else app1 - } + val app1 = app.withType(ownType).derivedApply(normalizedFun, typedArgs) + if (liftedDefs != null && liftedDefs.nonEmpty) Block(liftedDefs.toList, app1) + else app1 + } } /** Subclass of Application for type checking an Apply node with untyped arguments. */ - class ApplyToUntyped(app: untpd.Apply, fun: tpd.Tree, methRef: TermRef, args: List[untpd.Tree], resultType: Type)(implicit ctx: Context) + class ApplyToUntyped(app: untpd.Apply, fun: Tree, methRef: TermRef, args: List[untpd.Tree], resultType: Type)(implicit ctx: Context) extends TypedApply(app, fun, methRef, args, resultType) { def typedArg(arg: untpd.Tree, formal: Type): TypedArg = typed(arg, formal) - def treeToArg(arg: tpd.Tree): untpd.Tree = untpd.TypedSplice(arg) + def treeToArg(arg: Tree): untpd.Tree = untpd.TypedSplice(arg) } /** Subclass of Application for type checking an Apply node with typed arguments. */ - class ApplyToTyped(app: untpd.Apply, fun: tpd.Tree, methRef: TermRef, args: List[tpd.Tree], resultType: Type)(implicit ctx: Context) + class ApplyToTyped(app: untpd.Apply, fun: Tree, methRef: TermRef, args: List[Tree], resultType: Type)(implicit ctx: Context) extends TypedApply(app, fun, methRef, args, resultType) { - def typedArg(arg: tpd.Tree, formal: Type): TypedArg = arg - def treeToArg(arg: tpd.Tree): tpd.Tree = arg + def typedArg(arg: Tree, formal: Type): TypedArg = arg + def treeToArg(arg: Tree): Tree = arg } - def typedApply(app: untpd.Apply, fun: tpd.Tree, methRef: TermRef, args: List[tpd.Tree], resultType: Type)(implicit ctx: Context): tpd.Tree = + def typedApply(app: untpd.Apply, fun: Tree, methRef: TermRef, args: List[Tree], resultType: Type)(implicit ctx: Context): Tree = new ApplyToTyped(app, fun, methRef, args, resultType).result - def typedApply(fun: tpd.Tree, methRef: TermRef, args: List[tpd.Tree], resultType: Type)(implicit ctx: Context): tpd.Tree = - typedApply(Apply(untpd.TypedSplice(fun), Nil), fun, methRef, args, resultType) + def typedApply(fun: Tree, methRef: TermRef, args: List[Tree], resultType: Type)(implicit ctx: Context): Tree = + typedApply(Trees.Apply(untpd.TypedSplice(fun), Nil), fun, methRef, args, resultType) + + def typedApply(tree: untpd.Apply, pt: Type)(implicit ctx: Context): Tree = { + if (ctx.mode is Mode.Pattern) + typedUnApply(tree.fun, tree.args, tree, pt) + else { + + def realApply(implicit ctx: Context) = { + val proto = new FunProtoType(tree.args, pt, this) + val fun1 = typedExpr(tree.fun, proto) + TreeInfo.methPart(fun1).tpe match { + case funRef: TermRef => + val app = + if (proto.argsAreTyped) new ApplyToTyped(tree, fun1, funRef, proto.typedArgs, pt) + else new ApplyToUntyped(tree, fun1, funRef, tree.args, pt) + val result = app.result + ConstFold(result) orElse result + case _ => + fun1.exprType match { + case ErrorType => + tree.withType(ErrorType) + } + } + } + + def typedOpAssign: Tree = { + val Apply(Select(lhs, name), rhss) = tree + val lhs1 = typedExpr(lhs) + val lifted = new mutable.ListBuffer[Tree] + val lhs2 = untpd.TypedSplice(liftApp(lifted, lhs1)) + val assign = Trees.Assign(lhs2, Trees.Apply(Trees.Select(lhs2, name.init), rhss)) + typed(assign) + } + + realApply + if (TreeInfo.isOpAssign(tree)) + tryEither { + implicit ctx => realApply + } { failed => + tryEither { + implicit ctx => typedOpAssign + } { _ => + failed.commit() + } + } + else realApply + } + } + + def typedTypeApply(tree: untpd.TypeApply, pt: Type)(implicit ctx: Context): Tree = { + val typedFn = typedExpr(tree.fun, PolyProtoType(tree.args.length, pt)) + val typedArgs = tree.args map (typedType(_)) + val ownType = typedFn.tpe.widen match { + case pt: PolyType => + checkBounds(typedArgs, pt, tree.pos) + pt.resultType.substParams(pt, typedArgs map (_.tpe)) + case _ => + ctx.error(s"${err.exprStr(typedFn)} does not take type parameters", tree.pos) + ErrorType + } + tree.withType(ownType).derivedTypeApply(typedFn, typedArgs) + } + + def typedUnApply(qual: untpd.Tree, args: List[untpd.Tree], tree: untpd.Apply, pt: Type)(implicit ctx: Context): Tree = { + + def unapplyArgs(unapplyResult: Type)(implicit ctx: Context): List[Type] = { + def recur(tp: Type): List[Type] = { + def nonOverloadedMember(name: Name) = { + val ref = tp member name + if (ref.isOverloaded) { + errorType(s"Overloaded reference to $ref is not allowed in extractor", tree.pos) + } + else + ref.info + } + + def productSelectors: List[Type] = { + val sels = for (n <- Iterator.from(0)) yield nonOverloadedMember(("_" + n).toTermName) + sels.takeWhile(_.exists).toList + } + def seqSelector = defn.RepeatedParamType.appliedTo(tp.elemType :: Nil) + + if (tp derivesFrom defn.ProductClass) productSelectors + else if (tp derivesFrom defn.SeqClass) seqSelector :: Nil + else if (tp.typeSymbol == defn.BooleanClass) Nil + else if (nonOverloadedMember(nme.isDefined).exists && + nonOverloadedMember(nme.get).exists) recur(nonOverloadedMember(nme.get)) + else { + ctx.error(s"${unapplyResult.show} is not a valid result type of an unapply method of an extractor", tree.pos) + Nil + } + } + + recur(unapplyResult) + } + + val fn = { + val dummyArg = untpd.TypedSplice(dummyTreeOfType(WildcardType)) + val unappProto = FunProtoType(dummyArg :: Nil, pt, this) + tryEither { + implicit ctx => typedExpr(Trees.Select(qual, nme.unapply), unappProto) + } { + s => tryEither { + implicit ctx => typedExpr(Trees.Select(qual, nme.unapplySeq), unappProto) // for backwards compatibility; will be dropped + } { + _ => errorTree(s.value, s"${qual.show} cannot be used as an extractor in a pattern because it lacks an unapply or unapplySeq method") + } + } + } + fn.tpe.widen match { + case mt: MethodType => + val ownType = mt.resultType + ownType <:< pt // done for registering the constraints; error message would come later + var argTypes = unapplyArgs(ownType) + val bunchedArgs = argTypes match { + case argType :: Nil if argType.isRepeatedParam => Trees.SeqLiteral(args) :: Nil + case _ => args + } + if (argTypes.length != bunchedArgs.length) { + ctx.error(s"wrong number of argument patterns for ${err.patternConstrStr(fn)}", tree.pos) + argTypes = argTypes.take(args.length) ++ + List.fill(argTypes.length - args.length)(WildcardType) + } + val typedArgs = (bunchedArgs, argTypes).zipped map (typed(_, _)) + Trees.UnApply(fn, typedArgs).withPos(tree.pos).withType(ownType) + case et: ErrorType => + tree.withType(ErrorType) + } + } /** Is given method reference applicable to argument types `args`? * @param resultType The expected result type of the application */ - def isApplicableToTrees(methRef: TermRef, args: List[tpd.Tree], resultType: Type)(implicit ctx: Context) = + def isApplicableToTrees(methRef: TermRef, args: List[Tree], resultType: Type)(implicit ctx: Context) = new ApplicableToTrees(methRef, args, resultType)(ctx.fresh.withNewTyperState).success /** Is given method reference applicable to arguments `args`? @@ -576,8 +713,8 @@ trait Applications extends Compatibility{ self: Typer => best :: asGood(alts1) } - private val dummyTree = Literal(Constant(null)) - def dummyTreeOfType(tp: Type): tpd.Tree = dummyTree withType tp + private val dummyTree = Trees.Literal(Constant(null)) + def dummyTreeOfType(tp: Type): Tree = dummyTree withType tp /** Resolve overloaded alternative `alts`, given expected type `pt`. */ def resolveOverloaded(alts: List[TermRef], pt: Type)(implicit ctx: Context): List[TermRef] = { @@ -595,7 +732,7 @@ trait Applications extends Compatibility{ self: Typer => /** The shape of given tree as a type; is more expensive than * typeShape but can can handle named arguments. */ - def treeShape(tree: untpd.Tree): tpd.Tree = tree match { + def treeShape(tree: untpd.Tree): Tree = tree match { case NamedArg(name, arg) => val argShape = treeShape(arg) tree.withType(argShape.tpe).derivedNamedArg(name, argShape) @@ -627,14 +764,14 @@ trait Applications extends Compatibility{ self: Typer => def narrowByShapes(alts: List[TermRef]): List[TermRef] = if (args exists (_.isInstanceOf[untpd.Function])) - if (args exists (_.isInstanceOf[NamedArg[_]])) + if (args exists (_.isInstanceOf[Trees.NamedArg[_]])) narrowByTrees(alts, args map treeShape, resultType) else narrowByTypes(alts, args map typeShape, resultType) else alts - def narrowByTrees(alts: List[TermRef], args: List[tpd.Tree], resultType: Type): List[TermRef] = + def narrowByTrees(alts: List[TermRef], args: List[Tree], resultType: Type): List[TermRef] = alts filter (isApplicableToTrees(_, args, resultType)) val alts1 = narrowBySize(alts) @@ -645,6 +782,12 @@ trait Applications extends Compatibility{ self: Typer => else narrowByTrees(alts2, pt.typedArgs, resultType) } + case pt @ PolyProtoType(nargs, _) => + alts filter ( alt => alt.widen match { + case PolyType(pnames) if pnames.length == nargs => true + case _ => false + }) + case defn.FunctionType(args, resultType) => narrowByTypes(alts, args, resultType) diff --git a/src/dotty/tools/dotc/typer/ErrorReporting.scala b/src/dotty/tools/dotc/typer/ErrorReporting.scala index ef6184394..e0ff8e351 100644 --- a/src/dotty/tools/dotc/typer/ErrorReporting.scala +++ b/src/dotty/tools/dotc/typer/ErrorReporting.scala @@ -13,9 +13,12 @@ object ErrorReporting { import tpd._ - def errorTree(tree: Trees.Tree[_], msg: => String)(implicit ctx: Context): tpd.Tree = { - ctx.error(msg, tree.pos) - tree withType ErrorType + def errorTree(tree: Tree, msg: => String)(implicit ctx: Context): tpd.Tree = + tree withType errorType(msg, tree.pos) + + def errorType(msg: => String, pos: Position)(implicit ctx: Context): ErrorType = { + ctx.error(msg, pos) + ErrorType } class Errors(implicit ctx: Context) { @@ -54,6 +57,10 @@ object ErrorReporting { case _ => anonymousTypeMemberStr(tp) } + def exprStr(tree: Tree): String = refStr(tree.tpe) + + def patternConstrStr(tree: Tree): String = ??? + def typeMismatch(tree: Tree, pt: Type): Tree = errorTree(tree, s"""type mismatch: diff --git a/src/dotty/tools/dotc/typer/Inferencing.scala b/src/dotty/tools/dotc/typer/Inferencing.scala index 9d244ea3e..1ae33d87a 100644 --- a/src/dotty/tools/dotc/typer/Inferencing.scala +++ b/src/dotty/tools/dotc/typer/Inferencing.scala @@ -3,11 +3,42 @@ package dotc package typer import core._ +import ast._ import Contexts._, Types._, Flags._, Denotations._, NameOps._, Symbols._ +import Trees._ import annotation.unchecked +import util.Positions._ +import Decorators._ object Inferencing { + import tpd._ + + def checkBounds(args: List[Tree], poly: PolyType, pos: Position)(implicit ctx: Context): Unit = { + + } + + def checkStable(tp: Type, pos: Position)(implicit ctx: Context): Unit = { + if (!tp.isStable) + ctx.error(s"Prefix ${tp.show} is not stable", pos) + tp + } + + def checkClassTypeWithStablePrefix(tp: Type, pos: Position)(implicit ctx: Context): ClassSymbol = tp.dealias match { + case tp: TypeRef if tp.symbol.isClass => + checkStable(tp.prefix, pos) + tp.symbol.asClass + case _: RefinedType | _: TypeVar | _: AnnotatedType => + checkClassTypeWithStablePrefix(tp.asInstanceOf[TypeProxy].underlying, pos) + case _ => + ctx.error(s"${tp.show} is not a class type", pos) + defn.ObjectClass + } + + def checkInstantiatable(cls: ClassSymbol, pos: Position): Unit = { + ??? + } + implicit class Infer(val ictx: Context) extends AnyVal { implicit private def ctx = ictx @@ -68,6 +99,7 @@ object Inferencing { case nil => actuals.isEmpty } + /* not needed right now def formalParameters[T](mtp: MethodType, actuals: List[T])(isRepeated: T => Boolean)(implicit ctx: Context) = if (mtp.isVarArgs && !(actuals.nonEmpty && isRepeated(actuals.last))) { diff --git a/src/dotty/tools/dotc/typer/Mode.scala b/src/dotty/tools/dotc/typer/Mode.scala index d71c0c020..fe2692a88 100644 --- a/src/dotty/tools/dotc/typer/Mode.scala +++ b/src/dotty/tools/dotc/typer/Mode.scala @@ -30,6 +30,7 @@ object Mode { val Type = newMode(1, "Type") val ImplicitsDisabled = newMode(2, "ImplicitsDisabled") + val InSuperInit = newMode(3, "inSuperInit") val PatternOrType = Pattern | Type }
\ 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 0b6aa3c9e..1279fcf03 100644 --- a/src/dotty/tools/dotc/typer/Namer.scala +++ b/src/dotty/tools/dotc/typer/Namer.scala @@ -211,7 +211,7 @@ class Namer { typer: Typer => else typeDefSig(tree, sym)(localContext.withNewScope) case imp: Import => val expr1 = typedAheadExpr(imp.expr) - ImportType(SharedTree(expr1)) + ImportType(tpd.SharedTree(expr1)) } sym.info = typeSig(original) diff --git a/src/dotty/tools/dotc/typer/Typer.scala b/src/dotty/tools/dotc/typer/Typer.scala index f99c08ecb..6d6211daf 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.Infer +import Inferencing._ import Contexts._ import Symbols._ import Types._ @@ -19,7 +19,7 @@ import NameOps._ import Flags._ import Decorators._ import ErrorReporting._ -import Applications.FunProtoType +import Applications.{FunProtoType, PolyProtoType} import EtaExpansion.etaExpand import util.Positions._ import util.SourcePosition @@ -31,6 +31,8 @@ trait TyperContextOps { ctx: Context => } object Typer { + import tpd._ + object BindingPrec { val definition = 4 val namedImport = 3 @@ -40,12 +42,19 @@ object Typer { def isImportPrec(prec: Int) = prec == namedImport || prec == wildImport } - implicit class TreeDecorator(tree: tpd.Tree) { + implicit class TreeDecorator(tree: Tree) { def exprType(implicit ctx: Context): Type = tree.tpe match { case tpe: TermRef if !tpe.symbol.isStable => tpe.info case tpe => tpe } } + + case class StateFul[T](value: T, state: TyperState) { + def commit()(implicit ctx: Context): T = { + state.commit() + value + } + } } class Typer extends Namer with Applications with Implicits { @@ -60,11 +69,15 @@ class Typer extends Namer with Applications with Implicits { private var importedFromRoot: Set[Symbol] = Set() def typedSelection(site: Type, name: Name, pos: Position)(implicit ctx: Context): Type = { - val ref = site.member(name) + val ref = + if (name == nme.CONSTRUCTOR) site.decl(name) + else site.member(name) if (ref.exists) NamedType(site, name).withDenot(ref) else { if (!site.isErroneous) - ctx.error(s"$name is not a member of ${site.show}", pos) + ctx.error( + if (name == nme.CONSTRUCTOR) s"${site.show} does not have a constructor" + else s"$name is not a member of ${site.show}", pos) ErrorType } } @@ -95,6 +108,21 @@ class Typer extends Namer with Applications with Implicits { tpe } + /** The qualifying class + * of a this or super with prefix `qual`. + * packageOk is equal false when qualifying class symbol + */ + def qualifyingClass(tree: untpd.Tree, qual: Name, packageOK: Boolean)(implicit ctx: Context): Symbol = + ctx.owner.enclosingClass.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 an outer reference. * * @param tree The tree representing the identifier. @@ -258,7 +286,7 @@ class Typer extends Namer with Applications with Implicits { val rawType = try findRef(NoType, BindingPrec.nothingBound, NoContext) finally importedFromRoot = saved - + val ownType = if (rawType.exists) checkAccessible(rawType, superAccess = false, tree.pos) else { @@ -275,21 +303,61 @@ class Typer extends Namer with Applications with Implicits { tree.withType(ownType).derivedSelect(qual1, tree.name) } - def typedApply(tree: untpd.Apply, pt: Type)(implicit ctx: Context): Tree = { - val proto = new FunProtoType(tree.args, pt, this) - val fun1 = typedExpr(tree.fun, proto) - TreeInfo.methPart(fun1).tpe match { - case funRef: TermRef => - val app = - if (proto.argsAreTyped) new ApplyToTyped(tree, fun1, funRef, proto.typedArgs, pt) - else new ApplyToUntyped(tree, fun1, funRef, tree.args, pt) - app.result - case _ => - fun1.exprType match { - case ErrorType => - tree.withType(ErrorType) - } + def typedThis(tree: untpd.This)(implicit ctx: Context): Tree = { + val cls = qualifyingClass(tree, tree.qual, packageOK = false) + tree.withType(cls.thisType) + } + + def typedSuper(tree: untpd.Super)(implicit ctx: Context): Tree = { + val mix = tree.mix + val qual1 = typed(tree.qual) + val cls = qual1.tpe.typeSymbol + + def findMixinSuper(site: Type): Type = site.parents filter (_.name == mix) match { + case p :: Nil => + p + case Nil => + errorType(s"$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 (ctx.mode is Mode.InSuperInit) cls.info.firstParent + else cls.info.parents.reduceLeft((x: Type, y: Type) => AndType(x, y)) + + tree.withType(SuperType(cls.thisType, owntype)).derivedSuper(qual1, mix) + } + + def typedLiteral(tree: untpd.Literal)(implicit ctx: Context) = + tree.withType(if (tree.const.tag == UnitTag) defn.UnitType else ConstantType(tree.const)) + + def typedNew(tree: untpd.New)(implicit ctx: Context) = { + val tpt1 = typedType(tree.tpt) + val cls = checkClassTypeWithStablePrefix(tpt1.tpe, tpt1.pos) + checkInstantiatable(cls, tpt1.pos) + tree.withType(tpt1.tpe).derivedNew(tpt1) + } + + def typedPair(tree: untpd.Pair)(implicit ctx: Context) = { + val left1 = typed(tree.left) + val right1 = typed(tree.right) + tree.withType(defn.PairType.appliedTo(left1.tpe :: right1.tpe :: Nil)).derivedPair(left1, right1) + } + + def TypedTyped(tree: untpd.Typed)(implicit ctx: Context) = { + val tpt1 = typedType(tree.tpt) + val expr1 = typedExpr(tree.expr, tpt1.tpe) + tree.withType(tpt1.tpe).derivedTyped(tpt1, expr1) + } + + def NamedArg(tree: untpd.NamedArg, pt: Type)(implicit ctx: Context) = { + val arg1 = typed(tree.arg, pt) + tree.withType(arg1.tpe).derivedNamedArg(tree.name, arg1) + } + + def Assign(tree: untpd.Assign)(implicit ctx: Context) = { + ??? } def typedModifiers(mods: untpd.Modifiers)(implicit ctx: Context): Modifiers = { @@ -428,29 +496,24 @@ class Typer extends Namer with Applications with Implicits { def typedPattern(tree: untpd.Tree, pt: Type = WildcardType)(implicit ctx: Context): Tree = typed(tree, pt)(ctx addMode Mode.Pattern) - def tryEither[T](op: Context => T)(fallBack: => T)(implicit ctx: Context) = { + def tryEither[T](op: Context => T)(fallBack: StateFul[T] => T)(implicit ctx: Context) = { val nestedCtx = ctx.fresh.withNewTyperState val result = op(nestedCtx) if (nestedCtx.reporter.hasErrors) - fallBack + fallBack(StateFul(result, nestedCtx.typerState)) else { nestedCtx.typerState.commit() result } } - def tryInsertApply(tree: Tree, pt: Type)(fallBack: => Tree)(implicit ctx: Context): Tree = + def tryInsertApply(tree: Tree, pt: Type)(fallBack: StateFul[Tree] => Tree)(implicit ctx: Context): Tree = tryEither { implicit ctx => typedSelect(Trees.Select(untpd.TypedSplice(tree), nme.apply), pt) } { fallBack } - def tryInsertApplyIfFunProto(tree: Tree, pt: Type)(fallBack: => Tree)(implicit ctx: Context): Tree = pt match { - case pt: FunProtoType => tryInsertApply(tree, pt)(fallBack) - case _ => fallBack - } - /** * (-1) For expressions with annotated types, let AnnotationCheckers decide what to do * (0) Convert expressions with constant types to literals (unless in interactive/scaladoc mode) @@ -501,10 +564,13 @@ class Typer extends Namer with Applications with Implicits { case alt :: Nil => adapt(tree.withType(alt), pt) case Nil => - tryInsertApplyIfFunProto(tree, pt) { + def noMatches = errorTree(tree, s"""none of the ${err.overloadedAltsStr(altDenots)} |match $expectedStr""".stripMargin) + pt match { + case pt: FunProtoType => tryInsertApply(tree, pt)(_ => noMatches) + case _ => noMatches } case alts => errorTree(tree, @@ -521,7 +587,7 @@ class Typer extends Namer with Applications with Implicits { case Apply(_, _) => " more" case _ => "" } - errorTree(tree, s"$fn does not take$more parameters") + _ => errorTree(tree, s"$fn does not take$more parameters") } } @@ -559,10 +625,13 @@ class Typer extends Namer with Applications with Implicits { tree.tpe.widen match { case ref: TermRef => adaptOverloaded(ref) - case pt: PolyType => - val tracked = ctx.track(pt) - val tvars = ctx.newTypeVars(tracked) - adapt(tpd.TypeApply(tree, tvars map (tpd.TypeTree(_))), pt) + case poly: PolyType => + if (pt.isInstanceOf[PolyProtoType]) tree + else { + val tracked = ctx.track(poly) + val tvars = ctx.newTypeVars(tracked) + adapt(tpd.TypeApply(tree, tvars map (tpd.TypeTree(_))), pt) + } case tp => pt match { case pt: FunProtoType => adaptToArgs(tp, pt) |