diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/dotty/tools/dotc/core/Types.scala | 10 | ||||
-rw-r--r-- | src/dotty/tools/dotc/printing/RefinedPrinter.scala | 12 | ||||
-rw-r--r-- | src/dotty/tools/dotc/typer/Applications.scala | 44 | ||||
-rw-r--r-- | src/dotty/tools/dotc/typer/Implicits.scala | 14 | ||||
-rw-r--r-- | src/dotty/tools/dotc/typer/ProtoTypes.scala | 41 | ||||
-rw-r--r-- | src/dotty/tools/dotc/typer/Typer.scala | 46 |
6 files changed, 108 insertions, 59 deletions
diff --git a/src/dotty/tools/dotc/core/Types.scala b/src/dotty/tools/dotc/core/Types.scala index 088a2e3af..36b546230 100644 --- a/src/dotty/tools/dotc/core/Types.scala +++ b/src/dotty/tools/dotc/core/Types.scala @@ -756,6 +756,11 @@ object Types { def typeParamNamed(name: TypeName)(implicit ctx: Context): Symbol = classSymbol.decls.lookup(name) orElse member(name).symbol + /** If this is a prototype with some ignored component, reveal one more + * layer of it. Otherwise the type itself. + */ + def deepenProto(implicit ctx: Context): Type = this + // ----- Substitutions ----------------------------------------------------- /** Substitute all types that refer in their symbol attribute to @@ -1057,12 +1062,13 @@ object Types { if (owner.isTerm) d else d.asSeenFrom(prefix) } - private def checkSymAssign(sym: Symbol) = + private def checkSymAssign(sym: Symbol)(implicit ctx: Context) = assert( (lastSymbol eq sym) || (lastSymbol eq null) || (lastSymbol.defRunId != sym.defRunId) || - (lastSymbol.defRunId == NoRunId), + (lastSymbol.defRunId == NoRunId) || + (lastSymbol.infoOrCompleter == ErrorType), s"data race? overwriting symbol of $this / ${this.getClass} / ${lastSymbol.id} / ${sym.id}") protected def sig: Signature = Signature.NotAMethod diff --git a/src/dotty/tools/dotc/printing/RefinedPrinter.scala b/src/dotty/tools/dotc/printing/RefinedPrinter.scala index dd8f04d92..c20598bb3 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._, Annotations.Annotation import StdNames.nme import ast.{Trees, untpd} import typer.Namer -import typer.ProtoTypes.{SelectionProto, ViewProto, FunProto} +import typer.ProtoTypes.{SelectionProto, ViewProto, FunProto, IgnoredProto} import Trees._ import scala.annotation.switch @@ -108,10 +108,6 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) { } return (toTextLocal(tycon) ~ "[" ~ Text(args map argText, ", ") ~ "]").close } - case tp: SelectionProto => - return toText(RefinedType(WildcardType, tp.name, tp.memberProto)) - case tp: ViewProto => - return toText(tp.argType) ~ " ?=>? " ~ toText(tp.resultType) case tp: TypeRef => if ((tp.symbol is TypeParam | TypeArgument) && !ctx.phase.erasedTypes) { return tp.info match { @@ -121,8 +117,14 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) { } case ExprType(result) => return "=> " ~ toText(result) + case tp: SelectionProto => + return toText(RefinedType(WildcardType, tp.name, tp.memberProto)) + case tp: ViewProto => + return toText(tp.argType) ~ " ?=>? " ~ toText(tp.resultType) case FunProto(args, resultType, _) => return "funproto(" ~ toTextGlobal(args, ", ") ~ "):" ~ toText(resultType) + case tp: IgnoredProto => + return "?" case _ => } super.toText(tp) diff --git a/src/dotty/tools/dotc/typer/Applications.scala b/src/dotty/tools/dotc/typer/Applications.scala index 0f47336fc..92acb7939 100644 --- a/src/dotty/tools/dotc/typer/Applications.scala +++ b/src/dotty/tools/dotc/typer/Applications.scala @@ -434,7 +434,7 @@ trait Applications extends Compatibility { self: Typer => def typedApply(tree: untpd.Apply, pt: Type)(implicit ctx: Context): Tree = { def realApply(implicit ctx: Context): Tree = track("realApply") { - var proto = new FunProto(tree.args, pt, this) + var proto = new FunProto(tree.args, ignoreIfProto(pt), this) val fun1 = typedExpr(tree.fun, proto) // Warning: The following line is dirty and fragile. We record that auto-tupling was demanded as @@ -453,30 +453,13 @@ trait Applications extends Compatibility { self: Typer => else new ApplyToUntyped(tree, fun1, funRef, proto, pt) val result = app.result ConstFold(result) - } { (failedVal, failedState) => fun1 match { - case Select(qual, name) => - // try with prototype `[].name(args)`, this might succeed by inserting an - // implicit conversion around []. (an example is Int + BigInt). - tryEither { implicit ctx => - val simpleFunProto = new FunProto(tree.args, WildcardType, this) // drop result type, because views are disabled - val selProto = SelectionProto(name, simpleFunProto, NoViewsAllowed) - val qual1 = adaptInterpolated(qual, selProto) - if (qual eq qual1) ctx.error("no progress") - if (ctx.reporter.hasErrors) qual1 - else - typedApply( - cpy.Apply(tree, - cpy.Select(fun1, untpd.TypedSplice(qual1), name), - proto.typedArgs map untpd.TypedSplice), - pt) - } { (_, _) => - failedState.commit() - failedVal - } - case _ => - failedState.commit() - failedVal - } + } { (failedVal, failedState) => + val fun2 = tryInsertImplicit(fun1, proto) + if (fun1 eq fun2) { + failedState.commit() + failedVal + } else typedApply( + cpy.Apply(tree, untpd.TypedSplice(fun2), proto.typedArgs map untpd.TypedSplice), pt) } case _ => fun1.tpe match { @@ -771,7 +754,7 @@ trait Applications extends Compatibility { self: Typer => def isAsSpecific(alt1: TermRef, tp1: Type, alt2: TermRef, tp2: Type): Boolean = ctx.traceIndented(i"isAsSpecific $tp1 $tp2", overload) { tp1 match { case tp1: PolyType => def bounds(tparamRefs: List[TypeRef]) = tp1.paramBounds map (_.substParams(tp1, tparamRefs)) - val tparams = ctx.newTypeParams(alt1.symbol.owner, tp1.paramNames, EmptyFlags, bounds) + val tparams = ctx.newTypeParams(alt1.symbol, tp1.paramNames, EmptyFlags, bounds) isAsSpecific(alt1, tp1.instantiate(tparams map (_.typeRef)), alt2, tp2) case tp1: MethodType => def repeatedToSingle(tp: Type) = if (tp.isRepeatedParam) tp.argTypesHi.head else tp @@ -927,7 +910,14 @@ trait Applications extends Compatibility { self: Typer => alts filter (normalizedCompatible(_, pt)) } if (isDetermined(candidates)) candidates - else narrowMostSpecific(candidates) + else narrowMostSpecific(candidates) match { + case result @ (alt1 :: alt2 :: _) => + val deepPt = pt.deepenProto + if (deepPt ne pt) resolveOverloaded(alts, deepPt, targs) + else result + case result => + result + } } } diff --git a/src/dotty/tools/dotc/typer/Implicits.scala b/src/dotty/tools/dotc/typer/Implicits.scala index a32f552ed..d2a94e287 100644 --- a/src/dotty/tools/dotc/typer/Implicits.scala +++ b/src/dotty/tools/dotc/typer/Implicits.scala @@ -368,7 +368,10 @@ trait Implicits { self: Typer => return defn.isValueSubClass(from.symbol, to.symbol) case _ => } + case from: ValueType => + ; case _ => + return false } inferView(dummyTreeOfType(from), to)(ctx.fresh.setExploreTyperState).isInstanceOf[SearchSuccess] } @@ -410,12 +413,15 @@ trait Implicits { self: Typer => else new ImplicitSearch(pt, argument, pos) val result = isearch.bestImplicit result match { - case success: SearchSuccess => - // println(s"committing to ${success.tstate.show}") - success.tstate.commit() + case result: SearchSuccess => + result.tstate.commit() + result + case result: AmbiguousImplicits => + val deepPt = pt.deepenProto + if (deepPt ne pt) inferImplicit(deepPt, argument, pos) else result case _ => + result } - result } } diff --git a/src/dotty/tools/dotc/typer/ProtoTypes.scala b/src/dotty/tools/dotc/typer/ProtoTypes.scala index fab652849..1438f9e16 100644 --- a/src/dotty/tools/dotc/typer/ProtoTypes.scala +++ b/src/dotty/tools/dotc/typer/ProtoTypes.scala @@ -71,6 +71,23 @@ object ProtoTypes { override def viewExists(tp: Type, pt: Type)(implicit ctx: Context): Boolean = false } + /** A trait for prototypes that match all types */ + trait MatchAlways extends ProtoType { + def isMatchedBy(tp1: Type)(implicit ctx: Context) = true + def map(tm: TypeMap)(implicit ctx: Context): ProtoType = this + def fold[T](x: T, ta: TypeAccumulator[T])(implicit ctx: Context): T = x + } + + /** A class marking ignored prototypes that can be reviealed by `deepenProto` */ + case class IgnoredProto(proto: ProtoType) extends UncachedGroundType with MatchAlways { + override def deepenProto(implicit ctx: Context): Type = proto + } + + def ignoreIfProto(tp: Type): Type = tp match { + case proto: ProtoType => IgnoredProto(proto) + case _ => tp + } + /** A prototype for expressions [] that are part of a selection operation: * * [ ].name: proto @@ -107,6 +124,8 @@ object ProtoTypes { 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 deepenProto(implicit ctx: Context) = derivedSelectionProto(name, memberProto.deepenProto, compat) + override def computeHash = addDelta(doHash(name, memberProto), if (compat eq NoViewsAllowed) 1 else 0) } @@ -126,8 +145,7 @@ object ProtoTypes { 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) + case tp => SelectionProto(name, ignoreIfProto(tp), typer) } /** A prototype for expressions [] that are in some unspecified selection operation @@ -208,7 +226,10 @@ object ProtoTypes { 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) + def fold[T](x: T, ta: TypeAccumulator[T])(implicit ctx: Context): T = + ta(ta.foldOver(x, typedArgs.tpes), resultType) + + override def deepenProto(implicit ctx: Context) = derivedFunProto(args, resultType.deepenProto, typer) } /** A prototype for implicitly inferred views: @@ -226,10 +247,10 @@ object ProtoTypes { 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) + 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 + override def deepenProto(implicit ctx: Context) = derivedViewProto(argType, resultType.deepenProto) } class CachedViewProto(argType: Type, resultType: Type)(implicit ctx: Context) extends ViewProto(argType, resultType) { @@ -266,17 +287,15 @@ object ProtoTypes { def fold[T](x: T, ta: TypeAccumulator[T])(implicit ctx: Context): T = ta(ta.foldOver(x, targs), resultType) + + override def deepenProto(implicit ctx: Context) = derivedPolyProto(targs, resultType.deepenProto) } /** 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 - } + object AnyFunctionProto extends UncachedGroundType with MatchAlways /** Add all parameters in given polytype `pt` to the constraint's domain. * If the constraint contains already some of these parameters in its domain, diff --git a/src/dotty/tools/dotc/typer/Typer.scala b/src/dotty/tools/dotc/typer/Typer.scala index 944b44510..5d477193c 100644 --- a/src/dotty/tools/dotc/typer/Typer.scala +++ b/src/dotty/tools/dotc/typer/Typer.scala @@ -1009,15 +1009,41 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit } } - def tryInsertApply(tree: Tree, pt: Type)(fallBack: (Tree, TyperState) => Tree)(implicit ctx: Context): Tree = - tryEither { - implicit ctx => - val sel = typedSelect(untpd.Select(untpd.TypedSplice(tree), nme.apply), pt) - if (sel.tpe.isError) sel else adapt(sel, pt) - } { - fallBack + /** Try to insert `.apply` so that the result conforms to prototype `pt`. + * If that fails try to insert an implicit conversion around the qualifier + * part of `tree`. If either result conforms to `pt`, adapt it, else + * continue with `fallBack`. + */ + def tryInsertApplyOrImplicit(tree: Tree, pt: ProtoType)(fallBack: (Tree, TyperState) => Tree)(implicit ctx: Context): Tree = + tryEither { implicit ctx => + val sel = typedSelect(untpd.Select(untpd.TypedSplice(tree), nme.apply), pt) + if (sel.tpe.isError) sel else adapt(sel, pt) + } { (failedTree, failedState) => + val tree1 = tryInsertImplicit(tree, pt) + if (tree1 eq tree) fallBack(failedTree, failedState) + else adapt(tree1, pt) } + /** If this tree is a select node `qual.name`, try to insert an implicit conversion + * `c` around `qual` so that `c(qual).name` conforms to `pt`. If that fails + * return `tree` itself. + */ + def tryInsertImplicit(tree: Tree, pt: ProtoType)(implicit ctx: Context): Tree = ctx.traceIndented(i"try ins impl $tree $pt") { tree match { + case Select(qual, name) => + val normalizedProto = pt match { + case pt: FunProto => pt.derivedFunProto(pt.args, WildcardType, pt.typer) // drop result type, because views are disabled + case _ => pt + } + val qualProto = SelectionProto(name, normalizedProto, NoViewsAllowed) + tryEither { implicit ctx => + val qual1 = adaptInterpolated(qual, qualProto) + if ((qual eq qual1) || ctx.reporter.hasErrors) tree + else typedSelect(cpy.Select(tree, untpd.TypedSplice(qual1), name), pt) + } { (_, _) => tree + } + case _ => tree + }} + def adapt(tree: Tree, pt: Type)(implicit ctx: Context) = /*>|>*/ track("adapt") /*<|<*/ { /*>|>*/ ctx.traceIndented(i"adapting $tree of type ${tree.tpe} to $pt", typr, show = true) /*<|<*/ { interpolateUndetVars(tree) @@ -1087,7 +1113,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit def hasEmptyParams(denot: SingleDenotation) = denot.info.paramTypess == ListOfNil pt match { case pt: FunProto => - tryInsertApply(tree, pt)((_, _) => noMatches) + tryInsertApplyOrImplicit(tree, pt)((_, _) => noMatches) case _ => if (altDenots exists (_.info.paramTypess == ListOfNil)) typed(untpd.Apply(untpd.TypedSplice(tree), Nil), pt) @@ -1113,7 +1139,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit adaptToArgs(wtp, pt.tupled) else tree - case _ => tryInsertApply(tree, pt) { + case _ => tryInsertApplyOrImplicit(tree, pt) { val more = tree match { case Apply(_, _) => " more" case _ => "" @@ -1216,7 +1242,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit case pt: FunProto => adaptToArgs(wtp, pt) case pt: PolyProto => - tryInsertApply(tree, pt) { + tryInsertApplyOrImplicit(tree, pt) { (_, _) => tree // error will be reported in typedTypeApply } case _ => |